BindingUtils.cpp 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "BindingUtils.h"
  6. #include <algorithm>
  7. #include <stdarg.h>
  8. #include "mozilla/Assertions.h"
  9. #include "mozilla/DebugOnly.h"
  10. #include "mozilla/FloatingPoint.h"
  11. #include "mozilla/Preferences.h"
  12. #include "mozilla/SizePrintfMacros.h"
  13. #include "mozilla/Unused.h"
  14. #include "mozilla/UseCounter.h"
  15. #include "mozilla/dom/DocGroup.h"
  16. #include "AccessCheck.h"
  17. #include "jsfriendapi.h"
  18. #include "nsContentCreatorFunctions.h"
  19. #include "nsContentUtils.h"
  20. #include "nsGlobalWindow.h"
  21. #include "nsHTMLTags.h"
  22. #include "nsIDocShell.h"
  23. #include "nsIDOMGlobalPropertyInitializer.h"
  24. #include "nsIPermissionManager.h"
  25. #include "nsIPrincipal.h"
  26. #include "nsIXPConnect.h"
  27. #include "nsUTF8Utils.h"
  28. #include "WorkerPrivate.h"
  29. #include "WorkerRunnable.h"
  30. #include "WrapperFactory.h"
  31. #include "xpcprivate.h"
  32. #include "XrayWrapper.h"
  33. #include "nsPrintfCString.h"
  34. #include "mozilla/Sprintf.h"
  35. #include "nsGlobalWindow.h"
  36. #include "mozilla/dom/ScriptSettings.h"
  37. #include "mozilla/dom/CustomElementRegistry.h"
  38. #include "mozilla/dom/DOMError.h"
  39. #include "mozilla/dom/DOMErrorBinding.h"
  40. #include "mozilla/dom/DOMException.h"
  41. #include "mozilla/dom/ElementBinding.h"
  42. #include "mozilla/dom/HTMLObjectElement.h"
  43. #include "mozilla/dom/HTMLObjectElementBinding.h"
  44. #include "mozilla/dom/HTMLSharedObjectElement.h"
  45. #include "mozilla/dom/HTMLElementBinding.h"
  46. #include "mozilla/dom/HTMLEmbedElementBinding.h"
  47. #include "mozilla/dom/HTMLAppletElementBinding.h"
  48. #include "mozilla/dom/Promise.h"
  49. #include "mozilla/dom/ResolveSystemBinding.h"
  50. #include "mozilla/dom/WebIDLGlobalNameHash.h"
  51. #include "mozilla/dom/WorkerPrivate.h"
  52. #include "mozilla/dom/WorkerScope.h"
  53. #include "mozilla/dom/XrayExpandoClass.h"
  54. #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
  55. #include "nsDOMClassInfo.h"
  56. #include "ipc/ErrorIPCUtils.h"
  57. #include "mozilla/UseCounter.h"
  58. namespace mozilla {
  59. namespace dom {
  60. using namespace workers;
  61. // Forward declare GetConstructorObject methods.
  62. #define HTML_TAG(_tag, _classname, _interfacename) \
  63. namespace HTML##_interfacename##ElementBinding { \
  64. JSObject* GetConstructorObject(JSContext*); \
  65. }
  66. #define HTML_OTHER(_tag)
  67. #include "nsHTMLTagList.h"
  68. #undef HTML_TAG
  69. #undef HTML_OTHER
  70. typedef JSObject* (*constructorGetterCallback)(JSContext*);
  71. // Mapping of html tag and GetConstructorObject methods.
  72. #define HTML_TAG(_tag, _classname, _interfacename) HTML##_interfacename##ElementBinding::GetConstructorObject,
  73. #define HTML_OTHER(_tag) nullptr,
  74. // We use eHTMLTag_foo (where foo is the tag) which is defined in nsHTMLTags.h
  75. // to index into this array.
  76. static const constructorGetterCallback sConstructorGetterCallback[] = {
  77. HTMLUnknownElementBinding::GetConstructorObject,
  78. #include "nsHTMLTagList.h"
  79. #undef HTML_TAG
  80. #undef HTML_OTHER
  81. };
  82. const JSErrorFormatString ErrorFormatString[] = {
  83. #define MSG_DEF(_name, _argc, _exn, _str) \
  84. { #_name, _str, _argc, _exn },
  85. #include "mozilla/dom/Errors.msg"
  86. #undef MSG_DEF
  87. };
  88. #define MSG_DEF(_name, _argc, _exn, _str) \
  89. static_assert(_argc < JS::MaxNumErrorArguments, \
  90. #_name " must only have as many error arguments as the JS engine can support");
  91. #include "mozilla/dom/Errors.msg"
  92. #undef MSG_DEF
  93. const JSErrorFormatString*
  94. GetErrorMessage(void* aUserRef, const unsigned aErrorNumber)
  95. {
  96. MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString));
  97. return &ErrorFormatString[aErrorNumber];
  98. }
  99. uint16_t
  100. GetErrorArgCount(const ErrNum aErrorNumber)
  101. {
  102. return GetErrorMessage(nullptr, aErrorNumber)->argCount;
  103. }
  104. void
  105. binding_detail::ThrowErrorMessage(JSContext* aCx, const unsigned aErrorNumber, ...)
  106. {
  107. va_list ap;
  108. va_start(ap, aErrorNumber);
  109. JS_ReportErrorNumberUTF8VA(aCx, GetErrorMessage, nullptr, aErrorNumber, ap);
  110. va_end(ap);
  111. }
  112. bool
  113. ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
  114. bool aSecurityError, const char* aInterfaceName)
  115. {
  116. NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
  117. // This should only be called for DOM methods/getters/setters, which
  118. // are JSNative-backed functions, so we can assume that
  119. // JS_ValueToFunction and JS_GetFunctionDisplayId will both return
  120. // non-null and that JS_GetStringCharsZ returns non-null.
  121. JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
  122. MOZ_ASSERT(func);
  123. JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
  124. MOZ_ASSERT(funcName);
  125. nsAutoJSString funcNameStr;
  126. if (!funcNameStr.init(aCx, funcName)) {
  127. return false;
  128. }
  129. const ErrNum errorNumber = aSecurityError ?
  130. MSG_METHOD_THIS_UNWRAPPING_DENIED :
  131. MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
  132. MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2);
  133. JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
  134. static_cast<unsigned>(errorNumber),
  135. funcNameStr.get(), ifaceName.get());
  136. return false;
  137. }
  138. bool
  139. ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
  140. bool aSecurityError,
  141. prototypes::ID aProtoId)
  142. {
  143. return ThrowInvalidThis(aCx, aArgs, aSecurityError,
  144. NamesOfInterfacesWithProtos(aProtoId));
  145. }
  146. bool
  147. ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
  148. {
  149. nsPrintfCString errorMessage("%s attribute setter",
  150. NamesOfInterfacesWithProtos(aProtoId));
  151. return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
  152. }
  153. } // namespace dom
  154. namespace binding_danger {
  155. template<typename CleanupPolicy>
  156. struct TErrorResult<CleanupPolicy>::Message {
  157. Message() { MOZ_COUNT_CTOR(TErrorResult::Message); }
  158. ~Message() { MOZ_COUNT_DTOR(TErrorResult::Message); }
  159. nsTArray<nsString> mArgs;
  160. dom::ErrNum mErrorNumber;
  161. bool HasCorrectNumberOfArguments()
  162. {
  163. return GetErrorArgCount(mErrorNumber) == mArgs.Length();
  164. }
  165. };
  166. template<typename CleanupPolicy>
  167. nsTArray<nsString>&
  168. TErrorResult<CleanupPolicy>::CreateErrorMessageHelper(const dom::ErrNum errorNumber,
  169. nsresult errorType)
  170. {
  171. AssertInOwningThread();
  172. mResult = errorType;
  173. mMessage = new Message();
  174. mMessage->mErrorNumber = errorNumber;
  175. return mMessage->mArgs;
  176. }
  177. template<typename CleanupPolicy>
  178. void
  179. TErrorResult<CleanupPolicy>::SerializeMessage(IPC::Message* aMsg) const
  180. {
  181. using namespace IPC;
  182. AssertInOwningThread();
  183. MOZ_ASSERT(mUnionState == HasMessage);
  184. MOZ_ASSERT(mMessage);
  185. WriteParam(aMsg, mMessage->mArgs);
  186. WriteParam(aMsg, mMessage->mErrorNumber);
  187. }
  188. template<typename CleanupPolicy>
  189. bool
  190. TErrorResult<CleanupPolicy>::DeserializeMessage(const IPC::Message* aMsg,
  191. PickleIterator* aIter)
  192. {
  193. using namespace IPC;
  194. AssertInOwningThread();
  195. nsAutoPtr<Message> readMessage(new Message());
  196. if (!ReadParam(aMsg, aIter, &readMessage->mArgs) ||
  197. !ReadParam(aMsg, aIter, &readMessage->mErrorNumber)) {
  198. return false;
  199. }
  200. if (!readMessage->HasCorrectNumberOfArguments()) {
  201. return false;
  202. }
  203. MOZ_ASSERT(mUnionState == HasNothing);
  204. mMessage = readMessage.forget();
  205. #ifdef DEBUG
  206. mUnionState = HasMessage;
  207. #endif // DEBUG
  208. return true;
  209. }
  210. template<typename CleanupPolicy>
  211. void
  212. TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx)
  213. {
  214. AssertInOwningThread();
  215. MOZ_ASSERT(mMessage, "SetPendingExceptionWithMessage() can be called only once");
  216. MOZ_ASSERT(mUnionState == HasMessage);
  217. Message* message = mMessage;
  218. MOZ_RELEASE_ASSERT(message->HasCorrectNumberOfArguments());
  219. const uint32_t argCount = message->mArgs.Length();
  220. const char16_t* args[JS::MaxNumErrorArguments + 1];
  221. for (uint32_t i = 0; i < argCount; ++i) {
  222. args[i] = message->mArgs.ElementAt(i).get();
  223. }
  224. args[argCount] = nullptr;
  225. JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
  226. static_cast<unsigned>(message->mErrorNumber),
  227. argCount > 0 ? args : nullptr);
  228. ClearMessage();
  229. mResult = NS_OK;
  230. }
  231. template<typename CleanupPolicy>
  232. void
  233. TErrorResult<CleanupPolicy>::ClearMessage()
  234. {
  235. AssertInOwningThread();
  236. MOZ_ASSERT(IsErrorWithMessage());
  237. delete mMessage;
  238. mMessage = nullptr;
  239. #ifdef DEBUG
  240. mUnionState = HasNothing;
  241. #endif // DEBUG
  242. }
  243. template<typename CleanupPolicy>
  244. void
  245. TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
  246. {
  247. AssertInOwningThread();
  248. MOZ_ASSERT(mMightHaveUnreportedJSException,
  249. "Why didn't you tell us you planned to throw a JS exception?");
  250. ClearUnionData();
  251. // Make sure mJSException is initialized _before_ we try to root it. But
  252. // don't set it to exn yet, because we don't want to do that until after we
  253. // root.
  254. mJSException.asValueRef().setUndefined();
  255. if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
  256. // Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
  257. // in fact rooted mJSException.
  258. mResult = NS_ERROR_OUT_OF_MEMORY;
  259. } else {
  260. mJSException = exn;
  261. mResult = NS_ERROR_DOM_JS_EXCEPTION;
  262. #ifdef DEBUG
  263. mUnionState = HasJSException;
  264. #endif // DEBUG
  265. }
  266. }
  267. template<typename CleanupPolicy>
  268. void
  269. TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
  270. {
  271. AssertInOwningThread();
  272. MOZ_ASSERT(!mMightHaveUnreportedJSException,
  273. "Why didn't you tell us you planned to handle JS exceptions?");
  274. MOZ_ASSERT(mUnionState == HasJSException);
  275. JS::Rooted<JS::Value> exception(cx, mJSException);
  276. if (JS_WrapValue(cx, &exception)) {
  277. JS_SetPendingException(cx, exception);
  278. }
  279. mJSException = exception;
  280. // If JS_WrapValue failed, not much we can do about it... No matter
  281. // what, go ahead and unroot mJSException.
  282. js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
  283. mResult = NS_OK;
  284. #ifdef DEBUG
  285. mUnionState = HasNothing;
  286. #endif // DEBUG
  287. }
  288. template<typename CleanupPolicy>
  289. struct TErrorResult<CleanupPolicy>::DOMExceptionInfo {
  290. DOMExceptionInfo(nsresult rv, const nsACString& message)
  291. : mMessage(message)
  292. , mRv(rv)
  293. {}
  294. nsCString mMessage;
  295. nsresult mRv;
  296. };
  297. template<typename CleanupPolicy>
  298. void
  299. TErrorResult<CleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message* aMsg) const
  300. {
  301. using namespace IPC;
  302. AssertInOwningThread();
  303. MOZ_ASSERT(mDOMExceptionInfo);
  304. MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
  305. WriteParam(aMsg, mDOMExceptionInfo->mMessage);
  306. WriteParam(aMsg, mDOMExceptionInfo->mRv);
  307. }
  308. template<typename CleanupPolicy>
  309. bool
  310. TErrorResult<CleanupPolicy>::DeserializeDOMExceptionInfo(const IPC::Message* aMsg,
  311. PickleIterator* aIter)
  312. {
  313. using namespace IPC;
  314. AssertInOwningThread();
  315. nsCString message;
  316. nsresult rv;
  317. if (!ReadParam(aMsg, aIter, &message) ||
  318. !ReadParam(aMsg, aIter, &rv)) {
  319. return false;
  320. }
  321. MOZ_ASSERT(mUnionState == HasNothing);
  322. MOZ_ASSERT(IsDOMException());
  323. mDOMExceptionInfo = new DOMExceptionInfo(rv, message);
  324. #ifdef DEBUG
  325. mUnionState = HasDOMExceptionInfo;
  326. #endif // DEBUG
  327. return true;
  328. }
  329. template<typename CleanupPolicy>
  330. void
  331. TErrorResult<CleanupPolicy>::ThrowDOMException(nsresult rv,
  332. const nsACString& message)
  333. {
  334. AssertInOwningThread();
  335. ClearUnionData();
  336. mResult = NS_ERROR_DOM_DOMEXCEPTION;
  337. mDOMExceptionInfo = new DOMExceptionInfo(rv, message);
  338. #ifdef DEBUG
  339. mUnionState = HasDOMExceptionInfo;
  340. #endif
  341. }
  342. template<typename CleanupPolicy>
  343. void
  344. TErrorResult<CleanupPolicy>::SetPendingDOMException(JSContext* cx)
  345. {
  346. AssertInOwningThread();
  347. MOZ_ASSERT(mDOMExceptionInfo,
  348. "SetPendingDOMException() can be called only once");
  349. MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
  350. dom::Throw(cx, mDOMExceptionInfo->mRv, mDOMExceptionInfo->mMessage);
  351. ClearDOMExceptionInfo();
  352. mResult = NS_OK;
  353. }
  354. template<typename CleanupPolicy>
  355. void
  356. TErrorResult<CleanupPolicy>::ClearDOMExceptionInfo()
  357. {
  358. AssertInOwningThread();
  359. MOZ_ASSERT(IsDOMException());
  360. MOZ_ASSERT(mUnionState == HasDOMExceptionInfo || !mDOMExceptionInfo);
  361. delete mDOMExceptionInfo;
  362. mDOMExceptionInfo = nullptr;
  363. #ifdef DEBUG
  364. mUnionState = HasNothing;
  365. #endif // DEBUG
  366. }
  367. template<typename CleanupPolicy>
  368. void
  369. TErrorResult<CleanupPolicy>::ClearUnionData()
  370. {
  371. AssertInOwningThread();
  372. if (IsJSException()) {
  373. JSContext* cx = dom::danger::GetJSContext();
  374. MOZ_ASSERT(cx);
  375. mJSException.asValueRef().setUndefined();
  376. js::RemoveRawValueRoot(cx, &mJSException.asValueRef());
  377. #ifdef DEBUG
  378. mUnionState = HasNothing;
  379. #endif // DEBUG
  380. } else if (IsErrorWithMessage()) {
  381. ClearMessage();
  382. } else if (IsDOMException()) {
  383. ClearDOMExceptionInfo();
  384. }
  385. }
  386. template<typename CleanupPolicy>
  387. void
  388. TErrorResult<CleanupPolicy>::SetPendingGenericErrorException(JSContext* cx)
  389. {
  390. AssertInOwningThread();
  391. MOZ_ASSERT(!IsErrorWithMessage());
  392. MOZ_ASSERT(!IsJSException());
  393. MOZ_ASSERT(!IsDOMException());
  394. dom::Throw(cx, ErrorCode());
  395. mResult = NS_OK;
  396. }
  397. template<typename CleanupPolicy>
  398. TErrorResult<CleanupPolicy>&
  399. TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
  400. {
  401. AssertInOwningThread();
  402. aRHS.AssertInOwningThread();
  403. // Clear out any union members we may have right now, before we
  404. // start writing to it.
  405. ClearUnionData();
  406. #ifdef DEBUG
  407. mMightHaveUnreportedJSException = aRHS.mMightHaveUnreportedJSException;
  408. aRHS.mMightHaveUnreportedJSException = false;
  409. #endif
  410. if (aRHS.IsErrorWithMessage()) {
  411. mMessage = aRHS.mMessage;
  412. aRHS.mMessage = nullptr;
  413. } else if (aRHS.IsJSException()) {
  414. JSContext* cx = dom::danger::GetJSContext();
  415. MOZ_ASSERT(cx);
  416. mJSException.asValueRef().setUndefined();
  417. if (!js::AddRawValueRoot(cx, &mJSException.asValueRef(), "TErrorResult::mJSException")) {
  418. MOZ_CRASH("Could not root mJSException, we're about to OOM");
  419. }
  420. mJSException = aRHS.mJSException;
  421. aRHS.mJSException.asValueRef().setUndefined();
  422. js::RemoveRawValueRoot(cx, &aRHS.mJSException.asValueRef());
  423. } else if (aRHS.IsDOMException()) {
  424. mDOMExceptionInfo = aRHS.mDOMExceptionInfo;
  425. aRHS.mDOMExceptionInfo = nullptr;
  426. } else {
  427. // Null out the union on both sides for hygiene purposes.
  428. mMessage = aRHS.mMessage = nullptr;
  429. }
  430. #ifdef DEBUG
  431. mUnionState = aRHS.mUnionState;
  432. aRHS.mUnionState = HasNothing;
  433. #endif // DEBUG
  434. // Note: It's important to do this last, since this affects the condition
  435. // checks above!
  436. mResult = aRHS.mResult;
  437. aRHS.mResult = NS_OK;
  438. return *this;
  439. }
  440. template<typename CleanupPolicy>
  441. void
  442. TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
  443. {
  444. AssertInOwningThread();
  445. aRv.AssertInOwningThread();
  446. aRv.ClearUnionData();
  447. aRv.mResult = mResult;
  448. #ifdef DEBUG
  449. aRv.mMightHaveUnreportedJSException = mMightHaveUnreportedJSException;
  450. #endif
  451. if (IsErrorWithMessage()) {
  452. #ifdef DEBUG
  453. aRv.mUnionState = HasMessage;
  454. #endif
  455. aRv.mMessage = new Message();
  456. aRv.mMessage->mArgs = mMessage->mArgs;
  457. aRv.mMessage->mErrorNumber = mMessage->mErrorNumber;
  458. } else if (IsDOMException()) {
  459. #ifdef DEBUG
  460. aRv.mUnionState = HasDOMExceptionInfo;
  461. #endif
  462. aRv.mDOMExceptionInfo = new DOMExceptionInfo(mDOMExceptionInfo->mRv,
  463. mDOMExceptionInfo->mMessage);
  464. } else if (IsJSException()) {
  465. #ifdef DEBUG
  466. aRv.mUnionState = HasJSException;
  467. #endif
  468. JSContext* cx = dom::danger::GetJSContext();
  469. JS::Rooted<JS::Value> exception(cx, mJSException.asValueRef());
  470. aRv.ThrowJSException(cx, exception);
  471. }
  472. }
  473. template<typename CleanupPolicy>
  474. void
  475. TErrorResult<CleanupPolicy>::SuppressException()
  476. {
  477. AssertInOwningThread();
  478. WouldReportJSException();
  479. ClearUnionData();
  480. // We don't use AssignErrorCode, because we want to override existing error
  481. // states, which AssignErrorCode is not allowed to do.
  482. mResult = NS_OK;
  483. }
  484. template<typename CleanupPolicy>
  485. void
  486. TErrorResult<CleanupPolicy>::SetPendingException(JSContext* cx)
  487. {
  488. AssertInOwningThread();
  489. if (IsUncatchableException()) {
  490. // Nuke any existing exception on cx, to make sure we're uncatchable.
  491. JS_ClearPendingException(cx);
  492. // Don't do any reporting. Just return, to create an
  493. // uncatchable exception.
  494. mResult = NS_OK;
  495. return;
  496. }
  497. if (IsJSContextException()) {
  498. // Whatever we need to throw is on the JSContext already.
  499. MOZ_ASSERT(JS_IsExceptionPending(cx));
  500. mResult = NS_OK;
  501. return;
  502. }
  503. if (IsErrorWithMessage()) {
  504. SetPendingExceptionWithMessage(cx);
  505. return;
  506. }
  507. if (IsJSException()) {
  508. SetPendingJSException(cx);
  509. return;
  510. }
  511. if (IsDOMException()) {
  512. SetPendingDOMException(cx);
  513. return;
  514. }
  515. SetPendingGenericErrorException(cx);
  516. }
  517. template<typename CleanupPolicy>
  518. void
  519. TErrorResult<CleanupPolicy>::StealExceptionFromJSContext(JSContext* cx)
  520. {
  521. AssertInOwningThread();
  522. MOZ_ASSERT(mMightHaveUnreportedJSException,
  523. "Why didn't you tell us you planned to throw a JS exception?");
  524. JS::Rooted<JS::Value> exn(cx);
  525. if (!JS_GetPendingException(cx, &exn)) {
  526. ThrowUncatchableException();
  527. return;
  528. }
  529. ThrowJSException(cx, exn);
  530. JS_ClearPendingException(cx);
  531. }
  532. template<typename CleanupPolicy>
  533. void
  534. TErrorResult<CleanupPolicy>::NoteJSContextException(JSContext* aCx)
  535. {
  536. AssertInOwningThread();
  537. if (JS_IsExceptionPending(aCx)) {
  538. mResult = NS_ERROR_DOM_EXCEPTION_ON_JSCONTEXT;
  539. } else {
  540. mResult = NS_ERROR_UNCATCHABLE_EXCEPTION;
  541. }
  542. }
  543. template class TErrorResult<JustAssertCleanupPolicy>;
  544. template class TErrorResult<AssertAndSuppressCleanupPolicy>;
  545. template class TErrorResult<JustSuppressCleanupPolicy>;
  546. } // namespace binding_danger
  547. namespace dom {
  548. bool
  549. DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
  550. const ConstantSpec* cs)
  551. {
  552. JS::Rooted<JS::Value> value(cx);
  553. for (; cs->name; ++cs) {
  554. value = cs->value;
  555. bool ok =
  556. JS_DefineProperty(cx, obj, cs->name, value,
  557. JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
  558. if (!ok) {
  559. return false;
  560. }
  561. }
  562. return true;
  563. }
  564. static inline bool
  565. Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) {
  566. return JS_DefineFunctions(cx, obj, spec);
  567. }
  568. static inline bool
  569. Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) {
  570. return JS_DefineProperties(cx, obj, spec);
  571. }
  572. static inline bool
  573. Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) {
  574. return DefineConstants(cx, obj, spec);
  575. }
  576. template<typename T>
  577. bool
  578. DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj,
  579. const Prefable<T>* props)
  580. {
  581. MOZ_ASSERT(props);
  582. MOZ_ASSERT(props->specs);
  583. do {
  584. // Define if enabled
  585. if (props->isEnabled(cx, obj)) {
  586. if (!Define(cx, obj, props->specs)) {
  587. return false;
  588. }
  589. }
  590. } while ((++props)->specs);
  591. return true;
  592. }
  593. bool
  594. DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
  595. const Prefable<const JSFunctionSpec>* props)
  596. {
  597. return DefinePrefable(cx, obj, props);
  598. }
  599. bool
  600. DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
  601. const Prefable<const JSPropertySpec>* props)
  602. {
  603. return DefinePrefable(cx, obj, props);
  604. }
  605. // We should use JSFunction objects for interface objects, but we need a custom
  606. // hasInstance hook because we have new interface objects on prototype chains of
  607. // old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
  608. // reserved slots (e.g. for named constructors). So we define a custom
  609. // funToString ObjectOps member for interface objects.
  610. JSString*
  611. InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
  612. unsigned /* indent */)
  613. {
  614. const js::Class* clasp = js::GetObjectClass(aObject);
  615. MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
  616. const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
  617. DOMIfaceAndProtoJSClass::FromJSClass(clasp);
  618. return JS_NewStringCopyZ(aCx, ifaceAndProtoJSClass->mToString);
  619. }
  620. bool
  621. Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
  622. {
  623. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  624. const JS::Value& v =
  625. js::GetFunctionNativeReserved(&args.callee(),
  626. CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
  627. const JSNativeHolder* nativeHolder =
  628. static_cast<const JSNativeHolder*>(v.toPrivate());
  629. return (nativeHolder->mNative)(cx, argc, vp);
  630. }
  631. static JSObject*
  632. CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
  633. const JSNativeHolder* nativeHolder, unsigned ctorNargs)
  634. {
  635. JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
  636. JSFUN_CONSTRUCTOR, name);
  637. if (!fun) {
  638. return nullptr;
  639. }
  640. JSObject* constructor = JS_GetFunctionObject(fun);
  641. js::SetFunctionNativeReserved(constructor,
  642. CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
  643. js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
  644. return constructor;
  645. }
  646. static bool
  647. DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
  648. JS::Handle<JSObject*> constructor)
  649. {
  650. bool alreadyDefined;
  651. if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
  652. return false;
  653. }
  654. // This is Enumerable: False per spec.
  655. return alreadyDefined ||
  656. JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
  657. }
  658. static JSObject*
  659. CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
  660. JS::Handle<JSObject*> constructorProto,
  661. const js::Class* constructorClass,
  662. unsigned ctorNargs, const NamedConstructor* namedConstructors,
  663. JS::Handle<JSObject*> proto,
  664. const NativeProperties* properties,
  665. const NativeProperties* chromeOnlyProperties,
  666. const char* name, bool defineOnGlobal)
  667. {
  668. JS::Rooted<JSObject*> constructor(cx);
  669. MOZ_ASSERT(constructorProto);
  670. MOZ_ASSERT(constructorClass);
  671. constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
  672. constructorProto);
  673. if (!constructor) {
  674. return nullptr;
  675. }
  676. if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
  677. JSPROP_READONLY)) {
  678. return nullptr;
  679. }
  680. // Might as well intern, since we're going to need an atomized
  681. // version of name anyway when we stick our constructor on the
  682. // global.
  683. JS::Rooted<JSString*> nameStr(cx, JS_AtomizeAndPinString(cx, name));
  684. if (!nameStr) {
  685. return nullptr;
  686. }
  687. if (!JS_DefineProperty(cx, constructor, "name", nameStr, JSPROP_READONLY)) {
  688. return nullptr;
  689. }
  690. if (DOMIfaceAndProtoJSClass::FromJSClass(constructorClass)->wantsInterfaceHasInstance) {
  691. JS::Rooted<jsid> hasInstanceId(cx,
  692. SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)));
  693. if (!JS_DefineFunctionById(cx, constructor, hasInstanceId,
  694. InterfaceHasInstance, 1,
  695. // Flags match those of Function[Symbol.hasInstance]
  696. JSPROP_READONLY | JSPROP_PERMANENT)) {
  697. return nullptr;
  698. }
  699. }
  700. if (properties) {
  701. if (properties->HasStaticMethods() &&
  702. !DefinePrefable(cx, constructor, properties->StaticMethods())) {
  703. return nullptr;
  704. }
  705. if (properties->HasStaticAttributes() &&
  706. !DefinePrefable(cx, constructor, properties->StaticAttributes())) {
  707. return nullptr;
  708. }
  709. if (properties->HasConstants() &&
  710. !DefinePrefable(cx, constructor, properties->Constants())) {
  711. return nullptr;
  712. }
  713. }
  714. if (chromeOnlyProperties) {
  715. if (chromeOnlyProperties->HasStaticMethods() &&
  716. !DefinePrefable(cx, constructor,
  717. chromeOnlyProperties->StaticMethods())) {
  718. return nullptr;
  719. }
  720. if (chromeOnlyProperties->HasStaticAttributes() &&
  721. !DefinePrefable(cx, constructor,
  722. chromeOnlyProperties->StaticAttributes())) {
  723. return nullptr;
  724. }
  725. if (chromeOnlyProperties->HasConstants() &&
  726. !DefinePrefable(cx, constructor, chromeOnlyProperties->Constants())) {
  727. return nullptr;
  728. }
  729. }
  730. if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
  731. return nullptr;
  732. }
  733. if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
  734. return nullptr;
  735. }
  736. if (namedConstructors) {
  737. int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE;
  738. while (namedConstructors->mName) {
  739. JS::Rooted<JSObject*> namedConstructor(cx,
  740. CreateConstructor(cx, global, namedConstructors->mName,
  741. &namedConstructors->mHolder,
  742. namedConstructors->mNargs));
  743. if (!namedConstructor ||
  744. !JS_DefineProperty(cx, namedConstructor, "prototype",
  745. proto,
  746. JSPROP_PERMANENT | JSPROP_READONLY,
  747. JS_STUBGETTER, JS_STUBSETTER) ||
  748. (defineOnGlobal &&
  749. !DefineConstructor(cx, global, namedConstructors->mName,
  750. namedConstructor))) {
  751. return nullptr;
  752. }
  753. js::SetReservedSlot(constructor, namedConstructorSlot++,
  754. JS::ObjectValue(*namedConstructor));
  755. ++namedConstructors;
  756. }
  757. }
  758. return constructor;
  759. }
  760. static JSObject*
  761. CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
  762. JS::Handle<JSObject*> parentProto,
  763. const js::Class* protoClass,
  764. const NativeProperties* properties,
  765. const NativeProperties* chromeOnlyProperties,
  766. const char* const* unscopableNames,
  767. bool isGlobal)
  768. {
  769. JS::Rooted<JSObject*> ourProto(cx,
  770. JS_NewObjectWithUniqueType(cx, Jsvalify(protoClass), parentProto));
  771. if (!ourProto ||
  772. // We don't try to define properties on the global's prototype; those
  773. // properties go on the global itself.
  774. (!isGlobal &&
  775. !DefineProperties(cx, ourProto, properties, chromeOnlyProperties))) {
  776. return nullptr;
  777. }
  778. if (unscopableNames) {
  779. JS::Rooted<JSObject*> unscopableObj(cx, JS_NewPlainObject(cx));
  780. if (!unscopableObj) {
  781. return nullptr;
  782. }
  783. for (; *unscopableNames; ++unscopableNames) {
  784. if (!JS_DefineProperty(cx, unscopableObj, *unscopableNames,
  785. JS::TrueHandleValue, JSPROP_ENUMERATE)) {
  786. return nullptr;
  787. }
  788. }
  789. JS::Rooted<jsid> unscopableId(cx,
  790. SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::unscopables)));
  791. // Readonly and non-enumerable to match Array.prototype.
  792. if (!JS_DefinePropertyById(cx, ourProto, unscopableId, unscopableObj,
  793. JSPROP_READONLY)) {
  794. return nullptr;
  795. }
  796. }
  797. return ourProto;
  798. }
  799. bool
  800. DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
  801. const NativeProperties* properties,
  802. const NativeProperties* chromeOnlyProperties)
  803. {
  804. if (properties) {
  805. if (properties->HasMethods() &&
  806. !DefinePrefable(cx, obj, properties->Methods())) {
  807. return false;
  808. }
  809. if (properties->HasAttributes() &&
  810. !DefinePrefable(cx, obj, properties->Attributes())) {
  811. return false;
  812. }
  813. if (properties->HasConstants() &&
  814. !DefinePrefable(cx, obj, properties->Constants())) {
  815. return false;
  816. }
  817. }
  818. if (chromeOnlyProperties) {
  819. if (chromeOnlyProperties->HasMethods() &&
  820. !DefinePrefable(cx, obj, chromeOnlyProperties->Methods())) {
  821. return false;
  822. }
  823. if (chromeOnlyProperties->HasAttributes() &&
  824. !DefinePrefable(cx, obj, chromeOnlyProperties->Attributes())) {
  825. return false;
  826. }
  827. if (chromeOnlyProperties->HasConstants() &&
  828. !DefinePrefable(cx, obj, chromeOnlyProperties->Constants())) {
  829. return false;
  830. }
  831. }
  832. return true;
  833. }
  834. void
  835. CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
  836. JS::Handle<JSObject*> protoProto,
  837. const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
  838. JS::Handle<JSObject*> constructorProto,
  839. const js::Class* constructorClass,
  840. unsigned ctorNargs, const NamedConstructor* namedConstructors,
  841. JS::Heap<JSObject*>* constructorCache,
  842. const NativeProperties* properties,
  843. const NativeProperties* chromeOnlyProperties,
  844. const char* name, bool defineOnGlobal,
  845. const char* const* unscopableNames,
  846. bool isGlobal)
  847. {
  848. MOZ_ASSERT(protoClass || constructorClass,
  849. "Need at least one class!");
  850. MOZ_ASSERT(!((properties &&
  851. (properties->HasMethods() || properties->HasAttributes())) ||
  852. (chromeOnlyProperties &&
  853. (chromeOnlyProperties->HasMethods() ||
  854. chromeOnlyProperties->HasAttributes()))) || protoClass,
  855. "Methods or properties but no protoClass!");
  856. MOZ_ASSERT(!((properties &&
  857. (properties->HasStaticMethods() ||
  858. properties->HasStaticAttributes())) ||
  859. (chromeOnlyProperties &&
  860. (chromeOnlyProperties->HasStaticMethods() ||
  861. chromeOnlyProperties->HasStaticAttributes()))) ||
  862. constructorClass,
  863. "Static methods but no constructorClass!");
  864. MOZ_ASSERT(bool(name) == bool(constructorClass),
  865. "Must have name precisely when we have an interface object");
  866. MOZ_ASSERT(!protoClass == !protoCache,
  867. "If, and only if, there is an interface prototype object we need "
  868. "to cache it");
  869. MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
  870. "If, and only if, there is an interface object we need to cache "
  871. "it");
  872. MOZ_ASSERT(constructorProto || !constructorClass,
  873. "Must have a constructor proto if we plan to create a constructor "
  874. "object");
  875. JS::Rooted<JSObject*> proto(cx);
  876. if (protoClass) {
  877. proto =
  878. CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
  879. properties, chromeOnlyProperties,
  880. unscopableNames, isGlobal);
  881. if (!proto) {
  882. return;
  883. }
  884. *protoCache = proto;
  885. }
  886. else {
  887. MOZ_ASSERT(!proto);
  888. }
  889. JSObject* interface;
  890. if (constructorClass) {
  891. interface = CreateInterfaceObject(cx, global, constructorProto,
  892. constructorClass, ctorNargs,
  893. namedConstructors, proto, properties,
  894. chromeOnlyProperties, name,
  895. defineOnGlobal);
  896. if (!interface) {
  897. if (protoCache) {
  898. // If we fail we need to make sure to clear the value of protoCache we
  899. // set above.
  900. *protoCache = nullptr;
  901. }
  902. return;
  903. }
  904. *constructorCache = interface;
  905. }
  906. }
  907. bool
  908. NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
  909. JS::Handle<JSObject*> aScope,
  910. JS::MutableHandle<JS::Value> aRetval,
  911. xpcObjectHelper& aHelper,
  912. const nsIID* aIID,
  913. bool aAllowNativeWrapper)
  914. {
  915. js::AssertSameCompartment(aCx, aScope);
  916. nsresult rv;
  917. // Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
  918. // on all threads.
  919. nsWrapperCache *cache = aHelper.GetWrapperCache();
  920. if (cache && cache->IsDOMBinding()) {
  921. JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
  922. if (!obj) {
  923. obj = cache->WrapObject(aCx, nullptr);
  924. }
  925. if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) {
  926. return false;
  927. }
  928. if (obj) {
  929. aRetval.setObject(*obj);
  930. return true;
  931. }
  932. }
  933. MOZ_ASSERT(NS_IsMainThread());
  934. if (!XPCConvert::NativeInterface2JSObject(aRetval, nullptr, aHelper, aIID,
  935. aAllowNativeWrapper, &rv)) {
  936. // I can't tell if NativeInterface2JSObject throws JS exceptions
  937. // or not. This is a sloppy stab at the right semantics; the
  938. // method really ought to be fixed to behave consistently.
  939. if (!JS_IsExceptionPending(aCx)) {
  940. Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
  941. }
  942. return false;
  943. }
  944. return true;
  945. }
  946. bool
  947. TryPreserveWrapper(JSObject* obj)
  948. {
  949. MOZ_ASSERT(IsDOMObject(obj));
  950. if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) {
  951. nsWrapperCache* cache = nullptr;
  952. CallQueryInterface(native, &cache);
  953. if (cache) {
  954. cache->PreserveWrapper(native);
  955. }
  956. return true;
  957. }
  958. // If this DOMClass is not cycle collected, then it isn't wrappercached,
  959. // so it does not need to be preserved. If it is cycle collected, then
  960. // we can't tell if it is wrappercached or not, so we just return false.
  961. const DOMJSClass* domClass = GetDOMClass(obj);
  962. return domClass && !domClass->mParticipant;
  963. }
  964. // Can only be called with a DOM JSClass.
  965. bool
  966. InstanceClassHasProtoAtDepth(const js::Class* clasp,
  967. uint32_t protoID, uint32_t depth)
  968. {
  969. const DOMJSClass* domClass = DOMJSClass::FromJSClass(clasp);
  970. return static_cast<uint32_t>(domClass->mInterfaceChain[depth]) == protoID;
  971. }
  972. // Only set allowNativeWrapper to false if you really know you need it, if in
  973. // doubt use true. Setting it to false disables security wrappers.
  974. bool
  975. XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
  976. xpcObjectHelper& helper, const nsIID* iid,
  977. bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
  978. {
  979. if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
  980. allowNativeWrapper)) {
  981. return false;
  982. }
  983. #ifdef DEBUG
  984. JSObject* jsobj = rval.toObjectOrNull();
  985. if (jsobj &&
  986. js::GetGlobalForObjectCrossCompartment(jsobj) == jsobj) {
  987. NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
  988. "Why did we recreate this wrapper?");
  989. }
  990. #endif
  991. return true;
  992. }
  993. bool
  994. VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
  995. JS::MutableHandle<JS::Value> aRetval)
  996. {
  997. nsresult rv;
  998. if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
  999. // Does it throw? Who knows
  1000. if (!JS_IsExceptionPending(aCx)) {
  1001. Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
  1002. }
  1003. return false;
  1004. }
  1005. return true;
  1006. }
  1007. bool
  1008. QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
  1009. {
  1010. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1011. JS::Rooted<JS::Value> thisv(cx, JS_THIS(cx, vp));
  1012. if (thisv.isNull())
  1013. return false;
  1014. // Get the object. It might be a security wrapper, in which case we do a checked
  1015. // unwrap.
  1016. JS::Rooted<JSObject*> origObj(cx, &thisv.toObject());
  1017. JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(origObj,
  1018. /* stopAtWindowProxy = */ false));
  1019. if (!obj) {
  1020. JS_ReportErrorASCII(cx, "Permission denied to access object");
  1021. return false;
  1022. }
  1023. // Switch this to UnwrapDOMObjectToISupports once our global objects are
  1024. // using new bindings.
  1025. nsCOMPtr<nsISupports> native;
  1026. UnwrapArg<nsISupports>(obj, getter_AddRefs(native));
  1027. if (!native) {
  1028. return Throw(cx, NS_ERROR_FAILURE);
  1029. }
  1030. if (argc < 1) {
  1031. return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
  1032. }
  1033. if (!args[0].isObject()) {
  1034. return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
  1035. }
  1036. nsCOMPtr<nsIJSID> iid;
  1037. obj = &args[0].toObject();
  1038. if (NS_FAILED(UnwrapArg<nsIJSID>(obj, getter_AddRefs(iid)))) {
  1039. return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
  1040. }
  1041. MOZ_ASSERT(iid);
  1042. if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) {
  1043. nsresult rv;
  1044. nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
  1045. if (NS_FAILED(rv)) {
  1046. return Throw(cx, rv);
  1047. }
  1048. return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval());
  1049. }
  1050. nsCOMPtr<nsISupports> unused;
  1051. nsresult rv = native->QueryInterface(*iid->GetID(), getter_AddRefs(unused));
  1052. if (NS_FAILED(rv)) {
  1053. return Throw(cx, rv);
  1054. }
  1055. *vp = thisv;
  1056. return true;
  1057. }
  1058. void
  1059. GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
  1060. nsWrapperCache* aCache, nsIJSID* aIID,
  1061. JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
  1062. {
  1063. const nsID* iid = aIID->GetID();
  1064. RefPtr<nsISupports> result;
  1065. aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
  1066. if (aError.Failed()) {
  1067. return;
  1068. }
  1069. if (!WrapObject(aCx, result, iid, aRetval)) {
  1070. aError.Throw(NS_ERROR_FAILURE);
  1071. }
  1072. }
  1073. bool
  1074. ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
  1075. {
  1076. return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
  1077. }
  1078. bool
  1079. ThrowConstructorWithoutNew(JSContext* cx, const char* name)
  1080. {
  1081. return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name);
  1082. }
  1083. inline const NativePropertyHooks*
  1084. GetNativePropertyHooksFromConstructorFunction(JS::Handle<JSObject*> obj)
  1085. {
  1086. MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
  1087. const JS::Value& v =
  1088. js::GetFunctionNativeReserved(obj,
  1089. CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
  1090. const JSNativeHolder* nativeHolder =
  1091. static_cast<const JSNativeHolder*>(v.toPrivate());
  1092. return nativeHolder->mPropertyHooks;
  1093. }
  1094. inline const NativePropertyHooks*
  1095. GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
  1096. DOMObjectType& type)
  1097. {
  1098. const js::Class* clasp = js::GetObjectClass(obj);
  1099. const DOMJSClass* domClass = GetDOMClass(clasp);
  1100. if (domClass) {
  1101. bool isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
  1102. type = isGlobal ? eGlobalInstance : eInstance;
  1103. return domClass->mNativeHooks;
  1104. }
  1105. if (JS_ObjectIsFunction(cx, obj)) {
  1106. type = eInterface;
  1107. return GetNativePropertyHooksFromConstructorFunction(obj);
  1108. }
  1109. MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
  1110. const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
  1111. DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
  1112. type = ifaceAndProtoJSClass->mType;
  1113. return ifaceAndProtoJSClass->mNativeHooks;
  1114. }
  1115. static JSObject*
  1116. XrayCreateFunction(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1117. JSNativeWrapper native, unsigned nargs, JS::Handle<jsid> id)
  1118. {
  1119. JSFunction* fun;
  1120. if (JSID_IS_STRING(id)) {
  1121. fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0, id);
  1122. } else {
  1123. // Can't pass this id (probably a symbol) to NewFunctionByIdWithReserved;
  1124. // just use an empty name for lack of anything better.
  1125. fun = js::NewFunctionWithReserved(cx, native.op, nargs, 0, nullptr);
  1126. }
  1127. if (!fun) {
  1128. return nullptr;
  1129. }
  1130. SET_JITINFO(fun, native.info);
  1131. JSObject* obj = JS_GetFunctionObject(fun);
  1132. js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT,
  1133. JS::ObjectValue(*wrapper));
  1134. #ifdef DEBUG
  1135. js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF,
  1136. JS::ObjectValue(*obj));
  1137. #endif
  1138. return obj;
  1139. }
  1140. static bool
  1141. XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1142. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1143. const Prefable<const JSPropertySpec>* attributes,
  1144. const jsid* attributeIds,
  1145. const JSPropertySpec* attributeSpecs,
  1146. JS::MutableHandle<JS::PropertyDescriptor> desc,
  1147. bool& cacheOnHolder)
  1148. {
  1149. for (; attributes->specs; ++attributes) {
  1150. if (attributes->isEnabled(cx, obj)) {
  1151. // Set i to be the index into our full list of ids/specs that we're
  1152. // looking at now.
  1153. size_t i = attributes->specs - attributeSpecs;
  1154. for ( ; attributeIds[i] != JSID_VOID; ++i) {
  1155. if (id == attributeIds[i]) {
  1156. cacheOnHolder = true;
  1157. const JSPropertySpec& attrSpec = attributeSpecs[i];
  1158. // Because of centralization, we need to make sure we fault in the
  1159. // JitInfos as well. At present, until the JSAPI changes, the easiest
  1160. // way to do this is wrap them up as functions ourselves.
  1161. desc.setAttributes(attrSpec.flags);
  1162. // They all have getters, so we can just make it.
  1163. JS::Rooted<JSObject*> funobj(cx,
  1164. XrayCreateFunction(cx, wrapper, attrSpec.accessors.getter.native, 0, id));
  1165. if (!funobj)
  1166. return false;
  1167. desc.setGetterObject(funobj);
  1168. desc.attributesRef() |= JSPROP_GETTER;
  1169. if (attrSpec.accessors.setter.native.op) {
  1170. // We have a setter! Make it.
  1171. funobj =
  1172. XrayCreateFunction(cx, wrapper, attrSpec.accessors.setter.native, 1, id);
  1173. if (!funobj)
  1174. return false;
  1175. desc.setSetterObject(funobj);
  1176. desc.attributesRef() |= JSPROP_SETTER;
  1177. } else {
  1178. desc.setSetter(nullptr);
  1179. }
  1180. desc.object().set(wrapper);
  1181. return true;
  1182. }
  1183. }
  1184. }
  1185. }
  1186. return true;
  1187. }
  1188. static bool
  1189. XrayResolveMethod(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1190. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1191. const Prefable<const JSFunctionSpec>* methods,
  1192. const jsid* methodIds,
  1193. const JSFunctionSpec* methodSpecs,
  1194. JS::MutableHandle<JS::PropertyDescriptor> desc,
  1195. bool& cacheOnHolder)
  1196. {
  1197. const Prefable<const JSFunctionSpec>* method;
  1198. for (method = methods; method->specs; ++method) {
  1199. if (method->isEnabled(cx, obj)) {
  1200. // Set i to be the index into our full list of ids/specs that we're
  1201. // looking at now.
  1202. size_t i = method->specs - methodSpecs;
  1203. for ( ; methodIds[i] != JSID_VOID; ++i) {
  1204. if (id == methodIds[i]) {
  1205. cacheOnHolder = true;
  1206. const JSFunctionSpec& methodSpec = methodSpecs[i];
  1207. JSObject *funobj;
  1208. if (methodSpec.selfHostedName) {
  1209. JSFunction* fun =
  1210. JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
  1211. methodSpec.nargs);
  1212. if (!fun) {
  1213. return false;
  1214. }
  1215. MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
  1216. MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
  1217. funobj = JS_GetFunctionObject(fun);
  1218. } else {
  1219. funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
  1220. methodSpec.nargs, id);
  1221. if (!funobj) {
  1222. return false;
  1223. }
  1224. }
  1225. desc.value().setObject(*funobj);
  1226. desc.setAttributes(methodSpec.flags);
  1227. desc.object().set(wrapper);
  1228. desc.setSetter(nullptr);
  1229. desc.setGetter(nullptr);
  1230. return true;
  1231. }
  1232. }
  1233. }
  1234. }
  1235. return true;
  1236. }
  1237. // Try to resolve a property as an unforgeable property from the given
  1238. // NativeProperties, if it's there. nativeProperties is allowed to be null (in
  1239. // which case we of course won't resolve anything).
  1240. static bool
  1241. XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1242. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1243. JS::MutableHandle<JS::PropertyDescriptor> desc,
  1244. bool& cacheOnHolder,
  1245. const NativeProperties* nativeProperties)
  1246. {
  1247. if (!nativeProperties) {
  1248. return true;
  1249. }
  1250. if (nativeProperties->HasUnforgeableAttributes()) {
  1251. if (!XrayResolveAttribute(cx, wrapper, obj, id,
  1252. nativeProperties->UnforgeableAttributes(),
  1253. nativeProperties->UnforgeableAttributeIds(),
  1254. nativeProperties->UnforgeableAttributeSpecs(),
  1255. desc, cacheOnHolder)) {
  1256. return false;
  1257. }
  1258. if (desc.object()) {
  1259. return true;
  1260. }
  1261. }
  1262. if (nativeProperties->HasUnforgeableMethods()) {
  1263. if (!XrayResolveMethod(cx, wrapper, obj, id,
  1264. nativeProperties->UnforgeableMethods(),
  1265. nativeProperties->UnforgeableMethodIds(),
  1266. nativeProperties->UnforgeableMethodSpecs(),
  1267. desc, cacheOnHolder)) {
  1268. return false;
  1269. }
  1270. if (desc.object()) {
  1271. return true;
  1272. }
  1273. }
  1274. return true;
  1275. }
  1276. static bool
  1277. XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1278. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1279. JS::MutableHandle<JS::PropertyDescriptor> desc,
  1280. bool& cacheOnHolder, DOMObjectType type,
  1281. const NativeProperties* nativeProperties)
  1282. {
  1283. bool hasMethods = false;
  1284. if (type == eInterface) {
  1285. hasMethods = nativeProperties->HasStaticMethods();
  1286. } else {
  1287. hasMethods = nativeProperties->HasMethods();
  1288. }
  1289. if (hasMethods) {
  1290. const Prefable<const JSFunctionSpec>* methods;
  1291. const jsid* methodIds;
  1292. const JSFunctionSpec* methodSpecs;
  1293. if (type == eInterface) {
  1294. methods = nativeProperties->StaticMethods();
  1295. methodIds = nativeProperties->StaticMethodIds();
  1296. methodSpecs = nativeProperties->StaticMethodSpecs();
  1297. } else {
  1298. methods = nativeProperties->Methods();
  1299. methodIds = nativeProperties->MethodIds();
  1300. methodSpecs = nativeProperties->MethodSpecs();
  1301. }
  1302. JS::Rooted<jsid> methodId(cx);
  1303. if (nativeProperties->iteratorAliasMethodIndex != -1 &&
  1304. id == SYMBOL_TO_JSID(
  1305. JS::GetWellKnownSymbol(cx, JS::SymbolCode::iterator))) {
  1306. methodId =
  1307. nativeProperties->MethodIds()[nativeProperties->iteratorAliasMethodIndex];
  1308. } else {
  1309. methodId = id;
  1310. }
  1311. if (!XrayResolveMethod(cx, wrapper, obj, methodId, methods, methodIds,
  1312. methodSpecs, desc, cacheOnHolder)) {
  1313. return false;
  1314. }
  1315. if (desc.object()) {
  1316. return true;
  1317. }
  1318. }
  1319. if (type == eInterface) {
  1320. if (nativeProperties->HasStaticAttributes()) {
  1321. if (!XrayResolveAttribute(cx, wrapper, obj, id,
  1322. nativeProperties->StaticAttributes(),
  1323. nativeProperties->StaticAttributeIds(),
  1324. nativeProperties->StaticAttributeSpecs(),
  1325. desc, cacheOnHolder)) {
  1326. return false;
  1327. }
  1328. if (desc.object()) {
  1329. return true;
  1330. }
  1331. }
  1332. } else {
  1333. if (nativeProperties->HasAttributes()) {
  1334. if (!XrayResolveAttribute(cx, wrapper, obj, id,
  1335. nativeProperties->Attributes(),
  1336. nativeProperties->AttributeIds(),
  1337. nativeProperties->AttributeSpecs(),
  1338. desc, cacheOnHolder)) {
  1339. return false;
  1340. }
  1341. if (desc.object()) {
  1342. return true;
  1343. }
  1344. }
  1345. }
  1346. if (nativeProperties->HasConstants()) {
  1347. const Prefable<const ConstantSpec>* constant;
  1348. for (constant = nativeProperties->Constants(); constant->specs; ++constant) {
  1349. if (constant->isEnabled(cx, obj)) {
  1350. // Set i to be the index into our full list of ids/specs that we're
  1351. // looking at now.
  1352. size_t i = constant->specs - nativeProperties->ConstantSpecs();
  1353. for ( ; nativeProperties->ConstantIds()[i] != JSID_VOID; ++i) {
  1354. if (id == nativeProperties->ConstantIds()[i]) {
  1355. cacheOnHolder = true;
  1356. desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
  1357. desc.object().set(wrapper);
  1358. desc.value().set(nativeProperties->ConstantSpecs()[i].value);
  1359. return true;
  1360. }
  1361. }
  1362. }
  1363. }
  1364. }
  1365. return true;
  1366. }
  1367. static bool
  1368. ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1369. JS::Handle<JSObject*> obj,
  1370. size_t protoAndIfaceCacheIndex, unsigned attrs,
  1371. JS::MutableHandle<JS::PropertyDescriptor> desc,
  1372. bool& cacheOnHolder)
  1373. {
  1374. JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
  1375. {
  1376. JSAutoCompartment ac(cx, global);
  1377. ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
  1378. JSObject* protoOrIface =
  1379. protoAndIfaceCache.EntrySlotIfExists(protoAndIfaceCacheIndex);
  1380. if (!protoOrIface) {
  1381. return false;
  1382. }
  1383. cacheOnHolder = true;
  1384. desc.object().set(wrapper);
  1385. desc.setAttributes(attrs);
  1386. desc.setGetter(nullptr);
  1387. desc.setSetter(nullptr);
  1388. desc.value().set(JS::ObjectValue(*protoOrIface));
  1389. }
  1390. return JS_WrapPropertyDescriptor(cx, desc);
  1391. }
  1392. #ifdef DEBUG
  1393. static void
  1394. DEBUG_CheckXBLCallable(JSContext *cx, JSObject *obj)
  1395. {
  1396. // In general, we shouldn't have cross-compartment wrappers here, because
  1397. // we should be running in an XBL scope, and the content prototype should
  1398. // contain wrappers to functions defined in the XBL scope. But if the node
  1399. // has been adopted into another compartment, those prototypes will now point
  1400. // to a different XBL scope (which is ok).
  1401. MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(obj),
  1402. xpc::IsContentXBLScope(js::GetObjectCompartment(js::UncheckedUnwrap(obj))));
  1403. MOZ_ASSERT(JS::IsCallable(obj));
  1404. }
  1405. static void
  1406. DEBUG_CheckXBLLookup(JSContext *cx, JS::PropertyDescriptor *desc)
  1407. {
  1408. if (!desc->obj)
  1409. return;
  1410. if (!desc->value.isUndefined()) {
  1411. MOZ_ASSERT(desc->value.isObject());
  1412. DEBUG_CheckXBLCallable(cx, &desc->value.toObject());
  1413. }
  1414. if (desc->getter) {
  1415. MOZ_ASSERT(desc->attrs & JSPROP_GETTER);
  1416. DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter));
  1417. }
  1418. if (desc->setter) {
  1419. MOZ_ASSERT(desc->attrs & JSPROP_SETTER);
  1420. DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter));
  1421. }
  1422. }
  1423. #else
  1424. #define DEBUG_CheckXBLLookup(a, b) {}
  1425. #endif
  1426. /* static */ bool
  1427. XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1428. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1429. JS::MutableHandle<JS::PropertyDescriptor> desc,
  1430. bool& cacheOnHolder)
  1431. {
  1432. cacheOnHolder = false;
  1433. DOMObjectType type;
  1434. const NativePropertyHooks *nativePropertyHooks =
  1435. GetNativePropertyHooks(cx, obj, type);
  1436. const NativePropertiesHolder& nativeProperties =
  1437. nativePropertyHooks->mNativeProperties;
  1438. ResolveOwnProperty resolveOwnProperty =
  1439. nativePropertyHooks->mResolveOwnProperty;
  1440. if (type == eNamedPropertiesObject) {
  1441. // None of these should be cached on the holder, since they're dynamic.
  1442. return resolveOwnProperty(cx, wrapper, obj, id, desc);
  1443. }
  1444. // Check for unforgeable properties first.
  1445. if (IsInstance(type)) {
  1446. const NativePropertiesHolder& nativeProperties =
  1447. nativePropertyHooks->mNativeProperties;
  1448. if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
  1449. nativeProperties.regular)) {
  1450. return false;
  1451. }
  1452. if (!desc.object() && xpc::AccessCheck::isChrome(wrapper) &&
  1453. !XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, cacheOnHolder,
  1454. nativeProperties.chromeOnly)) {
  1455. return false;
  1456. }
  1457. if (desc.object()) {
  1458. return true;
  1459. }
  1460. }
  1461. if (IsInstance(type)) {
  1462. if (resolveOwnProperty) {
  1463. if (!resolveOwnProperty(cx, wrapper, obj, id, desc)) {
  1464. return false;
  1465. }
  1466. if (desc.object()) {
  1467. // None of these should be cached on the holder, since they're dynamic.
  1468. return true;
  1469. }
  1470. }
  1471. // If we're a special scope for in-content XBL, our script expects to see
  1472. // the bound XBL methods and attributes when accessing content. However,
  1473. // these members are implemented in content via custom-spliced prototypes,
  1474. // and thus aren't visible through Xray wrappers unless we handle them
  1475. // explicitly. So we check if we're running in such a scope, and if so,
  1476. // whether the wrappee is a bound element. If it is, we do a lookup via
  1477. // specialized XBL machinery.
  1478. //
  1479. // While we have to do some sketchy walking through content land, we should
  1480. // be protected by read-only/non-configurable properties, and any functions
  1481. // we end up with should _always_ be living in our own scope (the XBL scope).
  1482. // Make sure to assert that.
  1483. JS::Rooted<JSObject*> maybeElement(cx, obj);
  1484. Element* element;
  1485. if (xpc::ObjectScope(wrapper)->IsContentXBLScope() &&
  1486. NS_SUCCEEDED(UNWRAP_OBJECT(Element, &maybeElement, element))) {
  1487. if (!nsContentUtils::LookupBindingMember(cx, element, id, desc)) {
  1488. return false;
  1489. }
  1490. DEBUG_CheckXBLLookup(cx, desc.address());
  1491. if (desc.object()) {
  1492. // XBL properties shouldn't be cached on the holder, as they might be
  1493. // shadowed by own properties returned from mResolveOwnProperty.
  1494. desc.object().set(wrapper);
  1495. return true;
  1496. }
  1497. }
  1498. // For non-global instance Xrays there are no other properties, so return
  1499. // here for them.
  1500. if (type != eGlobalInstance) {
  1501. return true;
  1502. }
  1503. } else if (type == eInterface) {
  1504. if (IdEquals(id, "prototype")) {
  1505. return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
  1506. ResolvePrototypeOrConstructor(cx, wrapper, obj,
  1507. nativePropertyHooks->mPrototypeID,
  1508. JSPROP_PERMANENT | JSPROP_READONLY,
  1509. desc, cacheOnHolder);
  1510. }
  1511. if (id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)) &&
  1512. DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
  1513. wantsInterfaceHasInstance) {
  1514. cacheOnHolder = true;
  1515. JSNativeWrapper interfaceHasInstanceWrapper = { InterfaceHasInstance,
  1516. nullptr };
  1517. JSObject* funObj = XrayCreateFunction(cx, wrapper,
  1518. interfaceHasInstanceWrapper, 1, id);
  1519. if (!funObj) {
  1520. return false;
  1521. }
  1522. desc.value().setObject(*funObj);
  1523. desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT);
  1524. desc.object().set(wrapper);
  1525. desc.setSetter(nullptr);
  1526. desc.setGetter(nullptr);
  1527. return true;
  1528. }
  1529. } else {
  1530. MOZ_ASSERT(IsInterfacePrototype(type));
  1531. if (IdEquals(id, "constructor")) {
  1532. return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
  1533. ResolvePrototypeOrConstructor(cx, wrapper, obj,
  1534. nativePropertyHooks->mConstructorID,
  1535. 0, desc, cacheOnHolder);
  1536. }
  1537. // The properties for globals live on the instance, so return here as there
  1538. // are no properties on their interface prototype object.
  1539. if (type == eGlobalInterfacePrototype) {
  1540. return true;
  1541. }
  1542. }
  1543. if (nativeProperties.regular &&
  1544. !XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
  1545. nativeProperties.regular)) {
  1546. return false;
  1547. }
  1548. if (!desc.object() &&
  1549. nativeProperties.chromeOnly &&
  1550. xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
  1551. !XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
  1552. nativeProperties.chromeOnly)) {
  1553. return false;
  1554. }
  1555. return true;
  1556. }
  1557. bool
  1558. XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1559. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1560. JS::Handle<JS::PropertyDescriptor> desc,
  1561. JS::ObjectOpResult &result, bool *defined)
  1562. {
  1563. if (!js::IsProxy(obj))
  1564. return true;
  1565. const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
  1566. return handler->defineProperty(cx, wrapper, id, desc, result, defined);
  1567. }
  1568. template<typename SpecType>
  1569. bool
  1570. XrayAttributeOrMethodKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1571. JS::Handle<JSObject*> obj,
  1572. const Prefable<const SpecType>* list,
  1573. const jsid* ids, const SpecType* specList,
  1574. unsigned flags, JS::AutoIdVector& props)
  1575. {
  1576. for (; list->specs; ++list) {
  1577. if (list->isEnabled(cx, obj)) {
  1578. // Set i to be the index into our full list of ids/specs that we're
  1579. // looking at now.
  1580. size_t i = list->specs - specList;
  1581. for ( ; ids[i] != JSID_VOID; ++i) {
  1582. // Skip non-enumerable properties and symbol-keyed properties unless
  1583. // they are specially requested via flags.
  1584. if (((flags & JSITER_HIDDEN) ||
  1585. (specList[i].flags & JSPROP_ENUMERATE)) &&
  1586. ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(ids[i])) &&
  1587. !props.append(ids[i])) {
  1588. return false;
  1589. }
  1590. }
  1591. }
  1592. }
  1593. return true;
  1594. }
  1595. #define ADD_KEYS_IF_DEFINED(FieldName) { \
  1596. if (nativeProperties->Has##FieldName##s() && \
  1597. !XrayAttributeOrMethodKeys(cx, wrapper, obj, \
  1598. nativeProperties->FieldName##s(), \
  1599. nativeProperties->FieldName##Ids(), \
  1600. nativeProperties->FieldName##Specs(), \
  1601. flags, props)) { \
  1602. return false; \
  1603. } \
  1604. }
  1605. bool
  1606. XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1607. JS::Handle<JSObject*> obj,
  1608. unsigned flags, JS::AutoIdVector& props,
  1609. DOMObjectType type,
  1610. const NativeProperties* nativeProperties)
  1611. {
  1612. MOZ_ASSERT(type != eNamedPropertiesObject);
  1613. if (IsInstance(type)) {
  1614. ADD_KEYS_IF_DEFINED(UnforgeableMethod);
  1615. ADD_KEYS_IF_DEFINED(UnforgeableAttribute);
  1616. if (type == eGlobalInstance) {
  1617. ADD_KEYS_IF_DEFINED(Method);
  1618. ADD_KEYS_IF_DEFINED(Attribute);
  1619. }
  1620. } else if (type == eInterface) {
  1621. ADD_KEYS_IF_DEFINED(StaticMethod);
  1622. ADD_KEYS_IF_DEFINED(StaticAttribute);
  1623. } else if (type != eGlobalInterfacePrototype) {
  1624. MOZ_ASSERT(IsInterfacePrototype(type));
  1625. ADD_KEYS_IF_DEFINED(Method);
  1626. ADD_KEYS_IF_DEFINED(Attribute);
  1627. }
  1628. if (nativeProperties->HasConstants()) {
  1629. const Prefable<const ConstantSpec>* constant;
  1630. for (constant = nativeProperties->Constants(); constant->specs; ++constant) {
  1631. if (constant->isEnabled(cx, obj)) {
  1632. // Set i to be the index into our full list of ids/specs that we're
  1633. // looking at now.
  1634. size_t i = constant->specs - nativeProperties->ConstantSpecs();
  1635. for ( ; nativeProperties->ConstantIds()[i] != JSID_VOID; ++i) {
  1636. if (!props.append(nativeProperties->ConstantIds()[i])) {
  1637. return false;
  1638. }
  1639. }
  1640. }
  1641. }
  1642. }
  1643. return true;
  1644. }
  1645. #undef ADD_KEYS_IF_DEFINED
  1646. bool
  1647. XrayOwnNativePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1648. const NativePropertyHooks* nativePropertyHooks,
  1649. DOMObjectType type, JS::Handle<JSObject*> obj,
  1650. unsigned flags, JS::AutoIdVector& props)
  1651. {
  1652. MOZ_ASSERT(type != eNamedPropertiesObject);
  1653. if (type == eInterface &&
  1654. nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
  1655. !AddStringToIDVector(cx, props, "prototype")) {
  1656. return false;
  1657. }
  1658. if (IsInterfacePrototype(type) &&
  1659. nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
  1660. (flags & JSITER_HIDDEN) &&
  1661. !AddStringToIDVector(cx, props, "constructor")) {
  1662. return false;
  1663. }
  1664. const NativePropertiesHolder& nativeProperties =
  1665. nativePropertyHooks->mNativeProperties;
  1666. if (nativeProperties.regular &&
  1667. !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
  1668. nativeProperties.regular)) {
  1669. return false;
  1670. }
  1671. if (nativeProperties.chromeOnly &&
  1672. xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
  1673. !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
  1674. nativeProperties.chromeOnly)) {
  1675. return false;
  1676. }
  1677. return true;
  1678. }
  1679. bool
  1680. XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1681. JS::Handle<JSObject*> obj,
  1682. unsigned flags, JS::AutoIdVector& props)
  1683. {
  1684. DOMObjectType type;
  1685. const NativePropertyHooks* nativePropertyHooks =
  1686. GetNativePropertyHooks(cx, obj, type);
  1687. EnumerateOwnProperties enumerateOwnProperties =
  1688. nativePropertyHooks->mEnumerateOwnProperties;
  1689. if (type == eNamedPropertiesObject) {
  1690. return enumerateOwnProperties(cx, wrapper, obj, props);
  1691. }
  1692. if (IsInstance(type)) {
  1693. // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1071189
  1694. // Should do something about XBL properties too.
  1695. if (enumerateOwnProperties &&
  1696. !enumerateOwnProperties(cx, wrapper, obj, props)) {
  1697. return false;
  1698. }
  1699. }
  1700. return type == eGlobalInterfacePrototype ||
  1701. XrayOwnNativePropertyKeys(cx, wrapper, nativePropertyHooks, type,
  1702. obj, flags, props);
  1703. }
  1704. const JSClass*
  1705. XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj)
  1706. {
  1707. DOMObjectType type;
  1708. const NativePropertyHooks* nativePropertyHooks =
  1709. GetNativePropertyHooks(cx, obj, type);
  1710. if (!IsInstance(type)) {
  1711. // Non-instances don't need any special expando classes.
  1712. return &DefaultXrayExpandoObjectClass;
  1713. }
  1714. return nativePropertyHooks->mXrayExpandoClass;
  1715. }
  1716. bool
  1717. XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
  1718. JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
  1719. JS::ObjectOpResult& opresult)
  1720. {
  1721. DOMObjectType type;
  1722. const NativePropertyHooks* nativePropertyHooks =
  1723. GetNativePropertyHooks(cx, obj, type);
  1724. if (!IsInstance(type) || !nativePropertyHooks->mDeleteNamedProperty) {
  1725. return opresult.succeed();
  1726. }
  1727. return nativePropertyHooks->mDeleteNamedProperty(cx, wrapper, obj, id,
  1728. opresult);
  1729. }
  1730. JSObject*
  1731. GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
  1732. bool* isXray)
  1733. {
  1734. if (!xpc::WrapperFactory::IsXrayWrapper(obj)) {
  1735. JSObject* retval = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
  1736. MOZ_ASSERT(IsDOMObject(retval));
  1737. *isXray = false;
  1738. return retval;
  1739. }
  1740. *isXray = true;
  1741. return xpc::EnsureXrayExpandoObject(cx, obj);;
  1742. }
  1743. DEFINE_XRAY_EXPANDO_CLASS(, DefaultXrayExpandoObjectClass, 0);
  1744. NativePropertyHooks sEmptyNativePropertyHooks = {
  1745. nullptr,
  1746. nullptr,
  1747. nullptr,
  1748. {
  1749. nullptr,
  1750. nullptr
  1751. },
  1752. prototypes::id::_ID_Count,
  1753. constructors::id::_ID_Count,
  1754. nullptr
  1755. };
  1756. const js::ClassOps sBoringInterfaceObjectClassClassOps = {
  1757. nullptr, /* addProperty */
  1758. nullptr, /* delProperty */
  1759. nullptr, /* getProperty */
  1760. nullptr, /* setProperty */
  1761. nullptr, /* enumerate */
  1762. nullptr, /* resolve */
  1763. nullptr, /* mayResolve */
  1764. nullptr, /* finalize */
  1765. ThrowingConstructor, /* call */
  1766. nullptr, /* hasInstance */
  1767. ThrowingConstructor, /* construct */
  1768. nullptr, /* trace */
  1769. };
  1770. const js::ObjectOps sInterfaceObjectClassObjectOps = {
  1771. nullptr, /* lookupProperty */
  1772. nullptr, /* defineProperty */
  1773. nullptr, /* hasProperty */
  1774. nullptr, /* getProperty */
  1775. nullptr, /* setProperty */
  1776. nullptr, /* getOwnPropertyDescriptor */
  1777. nullptr, /* deleteProperty */
  1778. nullptr, /* getElements */
  1779. nullptr, /* enumerate */
  1780. InterfaceObjectToString, /* funToString */
  1781. };
  1782. bool
  1783. GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
  1784. JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
  1785. bool* found, JS::MutableHandle<JS::Value> vp)
  1786. {
  1787. JS::Rooted<JSObject*> proto(cx);
  1788. if (!js::GetObjectProto(cx, proxy, &proto)) {
  1789. return false;
  1790. }
  1791. if (!proto) {
  1792. *found = false;
  1793. return true;
  1794. }
  1795. if (!JS_HasPropertyById(cx, proto, id, found)) {
  1796. return false;
  1797. }
  1798. if (!*found) {
  1799. return true;
  1800. }
  1801. return JS_ForwardGetPropertyTo(cx, proto, id, receiver, vp);
  1802. }
  1803. bool
  1804. HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
  1805. JS::Handle<jsid> id, bool* has)
  1806. {
  1807. JS::Rooted<JSObject*> proto(cx);
  1808. if (!js::GetObjectProto(cx, proxy, &proto)) {
  1809. return false;
  1810. }
  1811. if (!proto) {
  1812. *has = false;
  1813. return true;
  1814. }
  1815. return JS_HasPropertyById(cx, proto, id, has);
  1816. }
  1817. bool
  1818. AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
  1819. nsTArray<nsString>& names,
  1820. bool shadowPrototypeProperties,
  1821. JS::AutoIdVector& props)
  1822. {
  1823. for (uint32_t i = 0; i < names.Length(); ++i) {
  1824. JS::Rooted<JS::Value> v(cx);
  1825. if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
  1826. return false;
  1827. }
  1828. JS::Rooted<jsid> id(cx);
  1829. if (!JS_ValueToId(cx, v, &id)) {
  1830. return false;
  1831. }
  1832. bool shouldAppend = shadowPrototypeProperties;
  1833. if (!shouldAppend) {
  1834. bool has;
  1835. if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
  1836. return false;
  1837. }
  1838. shouldAppend = !has;
  1839. }
  1840. if (shouldAppend) {
  1841. if (!props.append(id)) {
  1842. return false;
  1843. }
  1844. }
  1845. }
  1846. return true;
  1847. }
  1848. bool
  1849. DictionaryBase::ParseJSON(JSContext* aCx,
  1850. const nsAString& aJSON,
  1851. JS::MutableHandle<JS::Value> aVal)
  1852. {
  1853. if (aJSON.IsEmpty()) {
  1854. return true;
  1855. }
  1856. return JS_ParseJSON(aCx, PromiseFlatString(aJSON).get(), aJSON.Length(), aVal);
  1857. }
  1858. bool
  1859. DictionaryBase::StringifyToJSON(JSContext* aCx,
  1860. JS::Handle<JSObject*> aObj,
  1861. nsAString& aJSON) const
  1862. {
  1863. return JS::ToJSONMaybeSafely(aCx, aObj, AppendJSONToString, &aJSON);
  1864. }
  1865. /* static */
  1866. bool
  1867. DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
  1868. uint32_t aDataLength,
  1869. void* aString)
  1870. {
  1871. nsAString* string = static_cast<nsAString*>(aString);
  1872. string->Append(aJSONData, aDataLength);
  1873. return true;
  1874. }
  1875. nsresult
  1876. ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
  1877. {
  1878. js::AssertSameCompartment(aCx, aObjArg);
  1879. // Check if we're anywhere near the stack limit before we reach the
  1880. // transplanting code, since it has no good way to handle errors. This uses
  1881. // the untrusted script limit, which is not strictly necessary since no
  1882. // actual script should run.
  1883. JS_CHECK_RECURSION_CONSERVATIVE(aCx, return NS_ERROR_FAILURE);
  1884. JS::Rooted<JSObject*> aObj(aCx, aObjArg);
  1885. const DOMJSClass* domClass = GetDOMClass(aObj);
  1886. // DOM things are always parented to globals.
  1887. JS::Rooted<JSObject*> oldParent(aCx,
  1888. js::GetGlobalForObjectCrossCompartment(aObj));
  1889. MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(oldParent) == oldParent);
  1890. JS::Rooted<JSObject*> newParent(aCx,
  1891. domClass->mGetAssociatedGlobal(aCx, aObj));
  1892. MOZ_ASSERT(JS_IsGlobalObject(newParent));
  1893. JSAutoCompartment oldAc(aCx, oldParent);
  1894. JSCompartment* oldCompartment = js::GetObjectCompartment(oldParent);
  1895. JSCompartment* newCompartment = js::GetObjectCompartment(newParent);
  1896. if (oldCompartment == newCompartment) {
  1897. MOZ_ASSERT(oldParent == newParent);
  1898. return NS_OK;
  1899. }
  1900. nsISupports* native = UnwrapDOMObjectToISupports(aObj);
  1901. if (!native) {
  1902. return NS_OK;
  1903. }
  1904. bool isProxy = js::IsProxy(aObj);
  1905. JS::Rooted<JSObject*> expandoObject(aCx);
  1906. if (isProxy) {
  1907. expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
  1908. }
  1909. JSAutoCompartment newAc(aCx, newParent);
  1910. // First we clone the reflector. We get a copy of its properties and clone its
  1911. // expando chain.
  1912. JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx);
  1913. if (!proto) {
  1914. return NS_ERROR_FAILURE;
  1915. }
  1916. JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto));
  1917. if (!newobj) {
  1918. return NS_ERROR_FAILURE;
  1919. }
  1920. JS::Rooted<JSObject*> propertyHolder(aCx);
  1921. JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj);
  1922. if (copyFrom) {
  1923. propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr);
  1924. if (!propertyHolder) {
  1925. return NS_ERROR_OUT_OF_MEMORY;
  1926. }
  1927. if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) {
  1928. return NS_ERROR_FAILURE;
  1929. }
  1930. } else {
  1931. propertyHolder = nullptr;
  1932. }
  1933. // Expandos from other compartments are attached to the target JS object.
  1934. // Copy them over, and let the old ones die a natural death.
  1935. // Note that at this point the DOM_OBJECT_SLOT for |newobj| has not been set.
  1936. // CloneExpandoChain() will use this property of |newobj| when it calls
  1937. // preserveWrapper() via attachExpandoObject() if |aObj| has expandos set, and
  1938. // preserveWrapper() will not do anything in this case. This is safe because
  1939. // if expandos are present then the wrapper will already have been preserved
  1940. // for this native.
  1941. if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) {
  1942. return NS_ERROR_FAILURE;
  1943. }
  1944. // We've set up |newobj|, so we make it own the native by setting its reserved
  1945. // slot and nulling out the reserved slot of |obj|.
  1946. //
  1947. // NB: It's important to do this _after_ copying the properties to
  1948. // propertyHolder. Otherwise, an object with |foo.x === foo| will
  1949. // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
  1950. js::SetReservedOrProxyPrivateSlot(newobj, DOM_OBJECT_SLOT,
  1951. js::GetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT));
  1952. js::SetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
  1953. aObj = xpc::TransplantObject(aCx, aObj, newobj);
  1954. if (!aObj) {
  1955. MOZ_CRASH();
  1956. }
  1957. nsWrapperCache* cache = nullptr;
  1958. CallQueryInterface(native, &cache);
  1959. bool preserving = cache->PreservingWrapper();
  1960. cache->SetPreservingWrapper(false);
  1961. cache->SetWrapper(aObj);
  1962. cache->SetPreservingWrapper(preserving);
  1963. if (propertyHolder) {
  1964. JS::Rooted<JSObject*> copyTo(aCx);
  1965. if (isProxy) {
  1966. copyTo = DOMProxyHandler::EnsureExpandoObject(aCx, aObj);
  1967. } else {
  1968. copyTo = aObj;
  1969. }
  1970. if (!copyTo || !JS_CopyPropertiesFrom(aCx, copyTo, propertyHolder)) {
  1971. MOZ_CRASH();
  1972. }
  1973. }
  1974. JS::Rooted<JSObject*> maybeObjLC(aCx, aObj);
  1975. nsObjectLoadingContent* htmlobject;
  1976. nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, &maybeObjLC, htmlobject);
  1977. if (NS_FAILED(rv)) {
  1978. rv = UnwrapObject<prototypes::id::HTMLEmbedElement,
  1979. HTMLSharedObjectElement>(&maybeObjLC, htmlobject);
  1980. if (NS_FAILED(rv)) {
  1981. rv = UnwrapObject<prototypes::id::HTMLAppletElement,
  1982. HTMLSharedObjectElement>(&maybeObjLC, htmlobject);
  1983. if (NS_FAILED(rv)) {
  1984. htmlobject = nullptr;
  1985. }
  1986. }
  1987. }
  1988. if (htmlobject) {
  1989. htmlobject->SetupProtoChain(aCx, aObj);
  1990. }
  1991. // Now we can just return the wrapper
  1992. return NS_OK;
  1993. }
  1994. GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
  1995. : mGlobalJSObject(aCx),
  1996. mCx(aCx),
  1997. mGlobalObject(nullptr)
  1998. {
  1999. MOZ_ASSERT(mCx);
  2000. JS::Rooted<JSObject*> obj(aCx, aObject);
  2001. if (js::IsWrapper(obj)) {
  2002. obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
  2003. if (!obj) {
  2004. // We should never end up here on a worker thread, since there shouldn't
  2005. // be any security wrappers to worry about.
  2006. if (!MOZ_LIKELY(NS_IsMainThread())) {
  2007. MOZ_CRASH();
  2008. }
  2009. Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
  2010. return;
  2011. }
  2012. }
  2013. mGlobalJSObject = js::GetGlobalForObjectCrossCompartment(obj);
  2014. }
  2015. nsISupports*
  2016. GlobalObject::GetAsSupports() const
  2017. {
  2018. if (mGlobalObject) {
  2019. return mGlobalObject;
  2020. }
  2021. MOZ_ASSERT(!js::IsWrapper(mGlobalJSObject));
  2022. // Most of our globals are DOM objects. Try that first. Note that this
  2023. // assumes that either the first nsISupports in the object is the canonical
  2024. // one or that we don't care about the canonical nsISupports here.
  2025. mGlobalObject = UnwrapDOMObjectToISupports(mGlobalJSObject);
  2026. if (mGlobalObject) {
  2027. return mGlobalObject;
  2028. }
  2029. MOZ_ASSERT(NS_IsMainThread(), "All our worker globals are DOM objects");
  2030. // Remove everything below here once all our global objects are using new
  2031. // bindings. If that ever happens; it would need to include Sandbox and
  2032. // BackstagePass.
  2033. // See whether mGlobalJSObject is an XPCWrappedNative. This will redo the
  2034. // IsWrapper bit above and the UnwrapDOMObjectToISupports in the case when
  2035. // we're not actually an XPCWrappedNative, but this should be a rare-ish case
  2036. // anyway.
  2037. nsCOMPtr<nsISupports> supp = xpc::UnwrapReflectorToISupports(mGlobalJSObject);
  2038. if (supp) {
  2039. // See documentation for mGlobalJSObject for why this assignment is OK.
  2040. mGlobalObject = supp;
  2041. return mGlobalObject;
  2042. }
  2043. // And now a final hack. Sandbox is not a reflector, but it does have an
  2044. // nsIGlobalObject hanging out in its private slot. Handle that case here,
  2045. // (though again, this will do the useless UnwrapDOMObjectToISupports if we
  2046. // got here for something that is somehow not a DOM object, not an
  2047. // XPCWrappedNative _and_ not a Sandbox).
  2048. if (XPCConvert::GetISupportsFromJSObject(mGlobalJSObject, &mGlobalObject)) {
  2049. return mGlobalObject;
  2050. }
  2051. MOZ_ASSERT(!mGlobalObject);
  2052. Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
  2053. return nullptr;
  2054. }
  2055. nsIPrincipal*
  2056. GlobalObject::GetSubjectPrincipal() const
  2057. {
  2058. if (!NS_IsMainThread()) {
  2059. return nullptr;
  2060. }
  2061. JSCompartment* compartment = js::GetContextCompartment(mCx);
  2062. MOZ_ASSERT(compartment);
  2063. JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
  2064. return nsJSPrincipals::get(principals);
  2065. }
  2066. static bool
  2067. CallOrdinaryHasInstance(JSContext* cx, JS::CallArgs& args)
  2068. {
  2069. JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
  2070. bool isInstance;
  2071. if (!JS::OrdinaryHasInstance(cx, thisObj, args.get(0), &isInstance)) {
  2072. return false;
  2073. }
  2074. args.rval().setBoolean(isInstance);
  2075. return true;
  2076. }
  2077. bool
  2078. InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp)
  2079. {
  2080. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  2081. // If the thing we were passed is not an object, return false like
  2082. // OrdinaryHasInstance does.
  2083. if (!args.get(0).isObject()) {
  2084. args.rval().setBoolean(false);
  2085. return true;
  2086. }
  2087. // If "this" is not an object, likewise return false (again, like
  2088. // OrdinaryHasInstance).
  2089. if (!args.thisv().isObject()) {
  2090. args.rval().setBoolean(false);
  2091. return true;
  2092. }
  2093. // If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
  2094. // constructor, so just fall back to OrdinaryHasInstance. But note that we
  2095. // should CheckedUnwrap here, because otherwise we won't get the right
  2096. // answers.
  2097. JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
  2098. if (!thisObj) {
  2099. // Just fall back on the normal thing, in case it still happens to work.
  2100. return CallOrdinaryHasInstance(cx, args);
  2101. }
  2102. const js::Class* thisClass = js::GetObjectClass(thisObj);
  2103. if (!IsDOMIfaceAndProtoClass(thisClass)) {
  2104. return CallOrdinaryHasInstance(cx, args);
  2105. }
  2106. const DOMIfaceAndProtoJSClass* clasp =
  2107. DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
  2108. // If "this" isn't a DOM constructor or is a constructor for an interface
  2109. // without a prototype, just fall back to OrdinaryHasInstance.
  2110. if (clasp->mType != eInterface ||
  2111. clasp->mPrototypeID == prototypes::id::_ID_Count) {
  2112. return CallOrdinaryHasInstance(cx, args);
  2113. }
  2114. JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
  2115. const DOMJSClass* domClass =
  2116. GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
  2117. if (domClass &&
  2118. domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
  2119. args.rval().setBoolean(true);
  2120. return true;
  2121. }
  2122. if (jsipc::IsWrappedCPOW(instance)) {
  2123. bool boolp = false;
  2124. if (!jsipc::DOMInstanceOf(cx, js::UncheckedUnwrap(instance), clasp->mPrototypeID,
  2125. clasp->mDepth, &boolp)) {
  2126. return false;
  2127. }
  2128. args.rval().setBoolean(boolp);
  2129. return true;
  2130. }
  2131. return CallOrdinaryHasInstance(cx, args);
  2132. }
  2133. bool
  2134. InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
  2135. JS::Handle<JSObject*> instance,
  2136. bool* bp)
  2137. {
  2138. const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
  2139. MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
  2140. "Why do we have a hasInstance hook if we don't have a prototype "
  2141. "ID?");
  2142. *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
  2143. return true;
  2144. }
  2145. bool
  2146. ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj)
  2147. {
  2148. JS::Rooted<JSObject*> rootedObj(cx, obj);
  2149. GlobalObject global(cx, rootedObj);
  2150. if (global.Failed()) {
  2151. return false;
  2152. }
  2153. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
  2154. if (window && window->GetDoc()) {
  2155. window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
  2156. }
  2157. return true;
  2158. }
  2159. bool
  2160. GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
  2161. nsIGlobalObject** globalObj)
  2162. {
  2163. // Be very careful to not get tricked here.
  2164. MOZ_ASSERT(NS_IsMainThread());
  2165. if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))) {
  2166. NS_RUNTIMEABORT("Should have a chrome object here");
  2167. }
  2168. // Look up the content-side object.
  2169. JS::Rooted<JS::Value> domImplVal(cx);
  2170. if (!JS_GetProperty(cx, obj, "__DOM_IMPL__", &domImplVal)) {
  2171. return false;
  2172. }
  2173. if (!domImplVal.isObject()) {
  2174. ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
  2175. return false;
  2176. }
  2177. // Go ahead and get the global from it. GlobalObject will handle
  2178. // doing unwrapping as needed.
  2179. GlobalObject global(cx, &domImplVal.toObject());
  2180. if (global.Failed()) {
  2181. return false;
  2182. }
  2183. DebugOnly<nsresult> rv = CallQueryInterface(global.GetAsSupports(), globalObj);
  2184. MOZ_ASSERT(NS_SUCCEEDED(rv));
  2185. MOZ_ASSERT(*globalObj);
  2186. return true;
  2187. }
  2188. already_AddRefed<nsIGlobalObject>
  2189. ConstructJSImplementation(const char* aContractId,
  2190. const GlobalObject& aGlobal,
  2191. JS::MutableHandle<JSObject*> aObject,
  2192. ErrorResult& aRv)
  2193. {
  2194. // Get the global object to use as a parent and for initialization.
  2195. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
  2196. if (!global) {
  2197. aRv.Throw(NS_ERROR_FAILURE);
  2198. return nullptr;
  2199. }
  2200. ConstructJSImplementation(aContractId, global, aObject, aRv);
  2201. if (aRv.Failed()) {
  2202. return nullptr;
  2203. }
  2204. return global.forget();
  2205. }
  2206. void
  2207. ConstructJSImplementation(const char* aContractId,
  2208. nsIGlobalObject* aGlobal,
  2209. JS::MutableHandle<JSObject*> aObject,
  2210. ErrorResult& aRv)
  2211. {
  2212. MOZ_ASSERT(NS_IsMainThread());
  2213. // Make sure to divorce ourselves from the calling JS while creating and
  2214. // initializing the object, so exceptions from that will get reported
  2215. // properly, since those are never exceptions that a spec wants to be thrown.
  2216. {
  2217. AutoNoJSAPI nojsapi;
  2218. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
  2219. if (!window->IsCurrentInnerWindow()) {
  2220. aRv.Throw(NS_ERROR_FAILURE);
  2221. return;
  2222. }
  2223. // Get the XPCOM component containing the JS implementation.
  2224. nsresult rv;
  2225. nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
  2226. if (!implISupports) {
  2227. nsPrintfCString msg("Failed to get JS implementation for contract \"%s\"",
  2228. aContractId);
  2229. NS_WARNING(msg.get());
  2230. aRv.Throw(rv);
  2231. return;
  2232. }
  2233. // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer
  2234. // and our global is a window.
  2235. nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
  2236. do_QueryInterface(implISupports);
  2237. if (gpi) {
  2238. JS::Rooted<JS::Value> initReturn(RootingCx());
  2239. rv = gpi->Init(window, &initReturn);
  2240. if (NS_FAILED(rv)) {
  2241. aRv.Throw(rv);
  2242. return;
  2243. }
  2244. // With JS-implemented WebIDL, the return value of init() is not used to determine
  2245. // if init() failed, so init() should only return undefined. Any kind of permission
  2246. // or pref checking must happen by adding an attribute to the WebIDL interface.
  2247. if (!initReturn.isUndefined()) {
  2248. MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
  2249. MOZ_CRASH();
  2250. }
  2251. }
  2252. // Extract the JS implementation from the XPCOM object.
  2253. nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
  2254. do_QueryInterface(implISupports, &rv);
  2255. MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
  2256. if (!implWrapped) {
  2257. aRv.Throw(rv);
  2258. return;
  2259. }
  2260. aObject.set(implWrapped->GetJSObject());
  2261. if (!aObject) {
  2262. aRv.Throw(NS_ERROR_FAILURE);
  2263. }
  2264. }
  2265. }
  2266. bool
  2267. NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
  2268. JS::MutableHandle<JS::Value> rval)
  2269. {
  2270. // ByteStrings are not UTF-8 encoded.
  2271. JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length());
  2272. if (!jsStr)
  2273. return false;
  2274. rval.setString(jsStr);
  2275. return true;
  2276. }
  2277. template<typename T> static void
  2278. NormalizeUSVStringInternal(T& aString)
  2279. {
  2280. char16_t* start = aString.BeginWriting();
  2281. // Must use const here because we can't pass char** to UTF16CharEnumerator as
  2282. // it expects const char**. Unclear why this is illegal...
  2283. const char16_t* nextChar = start;
  2284. const char16_t* end = aString.Data() + aString.Length();
  2285. while (nextChar < end) {
  2286. uint32_t enumerated = UTF16CharEnumerator::NextChar(&nextChar, end);
  2287. if (enumerated == UCS2_REPLACEMENT_CHAR) {
  2288. int32_t lastCharIndex = (nextChar - start) - 1;
  2289. start[lastCharIndex] = static_cast<char16_t>(enumerated);
  2290. }
  2291. }
  2292. }
  2293. void
  2294. NormalizeUSVString(nsAString& aString)
  2295. {
  2296. NormalizeUSVStringInternal(aString);
  2297. }
  2298. void
  2299. NormalizeUSVString(binding_detail::FakeString& aString)
  2300. {
  2301. NormalizeUSVStringInternal(aString);
  2302. }
  2303. bool
  2304. ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
  2305. bool nullable, nsACString& result)
  2306. {
  2307. JS::Rooted<JSString*> s(cx);
  2308. if (v.isString()) {
  2309. s = v.toString();
  2310. } else {
  2311. if (nullable && v.isNullOrUndefined()) {
  2312. result.SetIsVoid(true);
  2313. return true;
  2314. }
  2315. s = JS::ToString(cx, v);
  2316. if (!s) {
  2317. return false;
  2318. }
  2319. }
  2320. // Conversion from Javascript string to ByteString is only valid if all
  2321. // characters < 256. This is always the case for Latin1 strings.
  2322. size_t length;
  2323. if (!js::StringHasLatin1Chars(s)) {
  2324. // ThrowErrorMessage can GC, so we first scan the string for bad chars
  2325. // and report the error outside the AutoCheckCannotGC scope.
  2326. bool foundBadChar = false;
  2327. size_t badCharIndex;
  2328. char16_t badChar;
  2329. {
  2330. JS::AutoCheckCannotGC nogc;
  2331. const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
  2332. if (!chars) {
  2333. return false;
  2334. }
  2335. for (size_t i = 0; i < length; i++) {
  2336. if (chars[i] > 255) {
  2337. badCharIndex = i;
  2338. badChar = chars[i];
  2339. foundBadChar = true;
  2340. break;
  2341. }
  2342. }
  2343. }
  2344. if (foundBadChar) {
  2345. MOZ_ASSERT(badCharIndex < length);
  2346. MOZ_ASSERT(badChar > 255);
  2347. // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
  2348. // 20 digits, plus one more for the null terminator.
  2349. char index[21];
  2350. static_assert(sizeof(size_t) <= 8, "index array too small");
  2351. SprintfLiteral(index, "%" PRIuSIZE, badCharIndex);
  2352. // A char16_t is 16 bits long. The biggest unsigned 16 bit
  2353. // number (65,535) has 5 digits, plus one more for the null
  2354. // terminator.
  2355. char badCharArray[6];
  2356. static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
  2357. SprintfLiteral(badCharArray, "%d", badChar);
  2358. ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
  2359. return false;
  2360. }
  2361. } else {
  2362. length = js::GetStringLength(s);
  2363. }
  2364. static_assert(js::MaxStringLength < UINT32_MAX,
  2365. "length+1 shouldn't overflow");
  2366. if (!result.SetLength(length, fallible)) {
  2367. return false;
  2368. }
  2369. JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length);
  2370. return true;
  2371. }
  2372. void
  2373. FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
  2374. {
  2375. MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
  2376. mozilla::dom::DestroyProtoAndIfaceCache(aObj);
  2377. }
  2378. bool
  2379. ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
  2380. JS::Handle<jsid> aId, bool* aResolvedp)
  2381. {
  2382. MOZ_ASSERT(JS_IsGlobalObject(aObj),
  2383. "Should have a global here, since we plan to resolve standard "
  2384. "classes!");
  2385. return JS_ResolveStandardClass(aCx, aObj, aId, aResolvedp);
  2386. }
  2387. bool
  2388. MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj)
  2389. {
  2390. return JS_MayResolveStandardClass(aNames, aId, aMaybeObj);
  2391. }
  2392. bool
  2393. EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
  2394. {
  2395. MOZ_ASSERT(JS_IsGlobalObject(aObj),
  2396. "Should have a global here, since we plan to enumerate standard "
  2397. "classes!");
  2398. return JS_EnumerateStandardClasses(aCx, aObj);
  2399. }
  2400. bool
  2401. IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
  2402. uint32_t aNonExposedGlobals)
  2403. {
  2404. MOZ_ASSERT(aNonExposedGlobals, "Why did we get called?");
  2405. MOZ_ASSERT((aNonExposedGlobals &
  2406. ~(GlobalNames::Window |
  2407. GlobalNames::BackstagePass |
  2408. GlobalNames::DedicatedWorkerGlobalScope |
  2409. GlobalNames::SharedWorkerGlobalScope |
  2410. GlobalNames::ServiceWorkerGlobalScope |
  2411. GlobalNames::WorkerDebuggerGlobalScope |
  2412. GlobalNames::WorkletGlobalScope)) == 0,
  2413. "Unknown non-exposed global type");
  2414. const char* name = js::GetObjectClass(aGlobal)->name;
  2415. if ((aNonExposedGlobals & GlobalNames::Window) &&
  2416. !strcmp(name, "Window")) {
  2417. return true;
  2418. }
  2419. if ((aNonExposedGlobals & GlobalNames::BackstagePass) &&
  2420. !strcmp(name, "BackstagePass")) {
  2421. return true;
  2422. }
  2423. if ((aNonExposedGlobals & GlobalNames::DedicatedWorkerGlobalScope) &&
  2424. !strcmp(name, "DedicatedWorkerGlobalScope")) {
  2425. return true;
  2426. }
  2427. if ((aNonExposedGlobals & GlobalNames::SharedWorkerGlobalScope) &&
  2428. !strcmp(name, "SharedWorkerGlobalScope")) {
  2429. return true;
  2430. }
  2431. if ((aNonExposedGlobals & GlobalNames::ServiceWorkerGlobalScope) &&
  2432. !strcmp(name, "ServiceWorkerGlobalScope")) {
  2433. return true;
  2434. }
  2435. if ((aNonExposedGlobals & GlobalNames::WorkerDebuggerGlobalScope) &&
  2436. !strcmp(name, "WorkerDebuggerGlobalScopex")) {
  2437. return true;
  2438. }
  2439. if ((aNonExposedGlobals & GlobalNames::WorkletGlobalScope) &&
  2440. !strcmp(name, "WorkletGlobalScope")) {
  2441. return true;
  2442. }
  2443. return false;
  2444. }
  2445. void
  2446. HandlePrerenderingViolation(nsPIDOMWindowInner* aWindow)
  2447. {
  2448. // Freeze the window and its workers, and its children too.
  2449. aWindow->Freeze();
  2450. // Suspend event handling on the document
  2451. nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
  2452. if (doc) {
  2453. doc->SuppressEventHandling(nsIDocument::eEvents);
  2454. }
  2455. }
  2456. bool
  2457. EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj)
  2458. {
  2459. JS::Rooted<JSObject*> thisObj(aCx, js::CheckedUnwrap(aObj));
  2460. if (!thisObj) {
  2461. // Without a this object, we cannot check the safety.
  2462. return true;
  2463. }
  2464. nsGlobalWindow* window = xpc::WindowGlobalOrNull(thisObj);
  2465. if (!window) {
  2466. // Without a window, we cannot check the safety.
  2467. return true;
  2468. }
  2469. if (window->GetIsPrerendered()) {
  2470. HandlePrerenderingViolation(window->AsInner());
  2471. // When the bindings layer sees a false return value, it returns false form
  2472. // the JSNative in order to trigger an uncatchable exception.
  2473. return false;
  2474. }
  2475. return true;
  2476. }
  2477. bool
  2478. GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
  2479. {
  2480. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  2481. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  2482. prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  2483. if (!args.thisv().isObject()) {
  2484. return ThrowInvalidThis(cx, args, false, protoID);
  2485. }
  2486. JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  2487. // NOTE: we want to leave obj in its initial compartment, so don't want to
  2488. // pass it to UnwrapObject.
  2489. JS::Rooted<JSObject*> rootSelf(cx, obj);
  2490. void* self;
  2491. {
  2492. binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
  2493. nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
  2494. self,
  2495. protoID,
  2496. info->depth);
  2497. if (NS_FAILED(rv)) {
  2498. return ThrowInvalidThis(cx, args,
  2499. rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
  2500. protoID);
  2501. }
  2502. }
  2503. MOZ_ASSERT(info->type() == JSJitInfo::Getter);
  2504. JSJitGetterOp getter = info->getter;
  2505. bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
  2506. #ifdef DEBUG
  2507. if (ok) {
  2508. AssertReturnTypeMatchesJitinfo(info, args.rval());
  2509. }
  2510. #endif
  2511. return ok;
  2512. }
  2513. bool
  2514. GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
  2515. {
  2516. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  2517. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  2518. prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  2519. if (!args.thisv().isObject()) {
  2520. return ThrowInvalidThis(cx, args, false, protoID);
  2521. }
  2522. JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  2523. // NOTE: we want to leave obj in its initial compartment, so don't want to
  2524. // pass it to UnwrapObject.
  2525. JS::Rooted<JSObject*> rootSelf(cx, obj);
  2526. void* self;
  2527. {
  2528. binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
  2529. nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
  2530. self,
  2531. protoID,
  2532. info->depth);
  2533. if (NS_FAILED(rv)) {
  2534. return ThrowInvalidThis(cx, args,
  2535. rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
  2536. protoID);
  2537. }
  2538. }
  2539. if (args.length() == 0) {
  2540. return ThrowNoSetterArg(cx, protoID);
  2541. }
  2542. MOZ_ASSERT(info->type() == JSJitInfo::Setter);
  2543. JSJitSetterOp setter = info->setter;
  2544. if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
  2545. return false;
  2546. }
  2547. args.rval().setUndefined();
  2548. #ifdef DEBUG
  2549. AssertReturnTypeMatchesJitinfo(info, args.rval());
  2550. #endif
  2551. return true;
  2552. }
  2553. bool
  2554. GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
  2555. {
  2556. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  2557. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  2558. prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  2559. if (!args.thisv().isObject()) {
  2560. return ThrowInvalidThis(cx, args, false, protoID);
  2561. }
  2562. JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  2563. // NOTE: we want to leave obj in its initial compartment, so don't want to
  2564. // pass it to UnwrapObject.
  2565. JS::Rooted<JSObject*> rootSelf(cx, obj);
  2566. void* self;
  2567. {
  2568. binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
  2569. nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
  2570. self,
  2571. protoID,
  2572. info->depth);
  2573. if (NS_FAILED(rv)) {
  2574. return ThrowInvalidThis(cx, args,
  2575. rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
  2576. protoID);
  2577. }
  2578. }
  2579. MOZ_ASSERT(info->type() == JSJitInfo::Method);
  2580. JSJitMethodOp method = info->method;
  2581. bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
  2582. #ifdef DEBUG
  2583. if (ok) {
  2584. AssertReturnTypeMatchesJitinfo(info, args.rval());
  2585. }
  2586. #endif
  2587. return ok;
  2588. }
  2589. bool
  2590. GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
  2591. {
  2592. // Make sure to save the callee before someone maybe messes with rval().
  2593. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  2594. JS::Rooted<JSObject*> callee(cx, &args.callee());
  2595. // We could invoke GenericBindingMethod here, but that involves an
  2596. // extra call. Manually inline it instead.
  2597. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  2598. prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
  2599. if (!args.thisv().isObject()) {
  2600. ThrowInvalidThis(cx, args, false, protoID);
  2601. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  2602. args.rval());
  2603. }
  2604. JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  2605. // NOTE: we want to leave obj in its initial compartment, so don't want to
  2606. // pass it to UnwrapObject.
  2607. JS::Rooted<JSObject*> rootSelf(cx, obj);
  2608. void* self;
  2609. {
  2610. binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
  2611. nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
  2612. self,
  2613. protoID,
  2614. info->depth);
  2615. if (NS_FAILED(rv)) {
  2616. ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
  2617. protoID);
  2618. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  2619. args.rval());
  2620. }
  2621. }
  2622. MOZ_ASSERT(info->type() == JSJitInfo::Method);
  2623. JSJitMethodOp method = info->method;
  2624. bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
  2625. if (ok) {
  2626. #ifdef DEBUG
  2627. AssertReturnTypeMatchesJitinfo(info, args.rval());
  2628. #endif
  2629. return true;
  2630. }
  2631. // Promise-returning methods always return objects
  2632. MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
  2633. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  2634. args.rval());
  2635. }
  2636. bool
  2637. StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp)
  2638. {
  2639. // Make sure to save the callee before someone maybe messes with rval().
  2640. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  2641. JS::Rooted<JSObject*> callee(cx, &args.callee());
  2642. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  2643. MOZ_ASSERT(info);
  2644. MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod);
  2645. bool ok = info->staticMethod(cx, argc, vp);
  2646. if (ok) {
  2647. return true;
  2648. }
  2649. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  2650. args.rval());
  2651. }
  2652. bool
  2653. ConvertExceptionToPromise(JSContext* cx,
  2654. JSObject* promiseScope,
  2655. JS::MutableHandle<JS::Value> rval)
  2656. {
  2657. {
  2658. JSAutoCompartment ac(cx, promiseScope);
  2659. JS::Rooted<JS::Value> exn(cx);
  2660. if (!JS_GetPendingException(cx, &exn)) {
  2661. // This is very important: if there is no pending exception here but we're
  2662. // ending up in this code, that means the callee threw an uncatchable
  2663. // exception. Just propagate that out as-is.
  2664. return false;
  2665. }
  2666. JS_ClearPendingException(cx);
  2667. JSObject* promise = JS::CallOriginalPromiseReject(cx, exn);
  2668. if (!promise) {
  2669. // We just give up. Put the exception back.
  2670. JS_SetPendingException(cx, exn);
  2671. return false;
  2672. }
  2673. rval.setObject(*promise);
  2674. }
  2675. // Now make sure we rewrap promise back into the compartment we want
  2676. return JS_WrapValue(cx, rval);
  2677. }
  2678. /* static */
  2679. void
  2680. CreateGlobalOptions<nsGlobalWindow>::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
  2681. {
  2682. xpc::TraceXPCGlobal(aTrc, aObj);
  2683. }
  2684. static bool sRegisteredDOMNames = false;
  2685. nsresult
  2686. RegisterDOMNames()
  2687. {
  2688. if (sRegisteredDOMNames) {
  2689. return NS_OK;
  2690. }
  2691. // Register new DOM bindings
  2692. WebIDLGlobalNameHash::Init();
  2693. nsresult rv = nsDOMClassInfo::Init();
  2694. if (NS_FAILED(rv)) {
  2695. NS_ERROR("Could not initialize nsDOMClassInfo");
  2696. return rv;
  2697. }
  2698. sRegisteredDOMNames = true;
  2699. return NS_OK;
  2700. }
  2701. /* static */
  2702. bool
  2703. CreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext* aCx,
  2704. JS::Handle<JSObject*> aGlobal)
  2705. {
  2706. nsresult rv = RegisterDOMNames();
  2707. if (NS_FAILED(rv)) {
  2708. return Throw(aCx, rv);
  2709. }
  2710. // Invoking the XPCWrappedNativeScope constructor automatically hooks it
  2711. // up to the compartment of aGlobal.
  2712. (void) new XPCWrappedNativeScope(aCx, aGlobal);
  2713. return true;
  2714. }
  2715. #ifdef DEBUG
  2716. void
  2717. AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
  2718. JS::Handle<JS::Value> aValue)
  2719. {
  2720. switch (aJitInfo->returnType()) {
  2721. case JSVAL_TYPE_UNKNOWN:
  2722. // Any value is good.
  2723. break;
  2724. case JSVAL_TYPE_DOUBLE:
  2725. // The value could actually be an int32 value as well.
  2726. MOZ_ASSERT(aValue.isNumber());
  2727. break;
  2728. case JSVAL_TYPE_INT32:
  2729. MOZ_ASSERT(aValue.isInt32());
  2730. break;
  2731. case JSVAL_TYPE_UNDEFINED:
  2732. MOZ_ASSERT(aValue.isUndefined());
  2733. break;
  2734. case JSVAL_TYPE_BOOLEAN:
  2735. MOZ_ASSERT(aValue.isBoolean());
  2736. break;
  2737. case JSVAL_TYPE_STRING:
  2738. MOZ_ASSERT(aValue.isString());
  2739. break;
  2740. case JSVAL_TYPE_NULL:
  2741. MOZ_ASSERT(aValue.isNull());
  2742. break;
  2743. case JSVAL_TYPE_OBJECT:
  2744. MOZ_ASSERT(aValue.isObject());
  2745. break;
  2746. default:
  2747. // Someone messed up their jitinfo type.
  2748. MOZ_ASSERT(false, "Unexpected JSValueType stored in jitinfo");
  2749. break;
  2750. }
  2751. }
  2752. #endif
  2753. bool
  2754. CallerSubsumes(JSObject *aObject)
  2755. {
  2756. nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
  2757. return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
  2758. }
  2759. nsresult
  2760. UnwrapArgImpl(JS::Handle<JSObject*> src,
  2761. const nsIID &iid,
  2762. void **ppArg)
  2763. {
  2764. if (!NS_IsMainThread()) {
  2765. return NS_ERROR_NOT_AVAILABLE;
  2766. }
  2767. nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(src);
  2768. if (iface) {
  2769. if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
  2770. return NS_ERROR_XPC_BAD_CONVERT_JS;
  2771. }
  2772. return NS_OK;
  2773. }
  2774. // Only allow XPCWrappedJS stuff in system code. Ideally we would remove this
  2775. // even there, but that involves converting some things to WebIDL callback
  2776. // interfaces and making some other things builtinclass...
  2777. if (!nsContentUtils::IsCallerChrome()) {
  2778. return NS_ERROR_XPC_BAD_CONVERT_JS;
  2779. }
  2780. RefPtr<nsXPCWrappedJS> wrappedJS;
  2781. nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, getter_AddRefs(wrappedJS));
  2782. if (NS_FAILED(rv) || !wrappedJS) {
  2783. return rv;
  2784. }
  2785. // We need to go through the QueryInterface logic to make this return
  2786. // the right thing for the various 'special' interfaces; e.g.
  2787. // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
  2788. // there is an outer to avoid nasty recursion.
  2789. return wrappedJS->QueryInterface(iid, ppArg);
  2790. }
  2791. nsresult
  2792. UnwrapXPConnectImpl(JSContext* cx,
  2793. JS::MutableHandle<JS::Value> src,
  2794. const nsIID &iid,
  2795. void **ppArg)
  2796. {
  2797. if (!NS_IsMainThread()) {
  2798. return NS_ERROR_NOT_AVAILABLE;
  2799. }
  2800. MOZ_ASSERT(src.isObject());
  2801. // Unwrap ourselves, because we're going to want access to the unwrapped
  2802. // object.
  2803. JS::Rooted<JSObject*> obj(cx,
  2804. js::CheckedUnwrap(&src.toObject(),
  2805. /* stopAtWindowProxy = */ false));
  2806. if (!obj) {
  2807. return NS_ERROR_NOT_AVAILABLE;
  2808. }
  2809. nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(obj);
  2810. if (!iface) {
  2811. return NS_ERROR_XPC_BAD_CONVERT_JS;
  2812. }
  2813. if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
  2814. return NS_ERROR_XPC_BAD_CONVERT_JS;
  2815. }
  2816. // Now update our source to keep rooting our object.
  2817. src.setObject(*obj);
  2818. return NS_OK;
  2819. }
  2820. nsresult
  2821. UnwrapWindowProxyImpl(JS::Handle<JSObject*> src,
  2822. nsPIDOMWindowOuter** ppArg)
  2823. {
  2824. nsCOMPtr<nsPIDOMWindowInner> inner;
  2825. nsresult rv = UnwrapArg<nsPIDOMWindowInner>(src, getter_AddRefs(inner));
  2826. NS_ENSURE_SUCCESS(rv, rv);
  2827. nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
  2828. outer.forget(ppArg);
  2829. return NS_OK;
  2830. }
  2831. bool
  2832. SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
  2833. JS::Handle<jsid> id, bool* resolvedp)
  2834. {
  2835. if (!ResolveGlobal(cx, obj, id, resolvedp)) {
  2836. return false;
  2837. }
  2838. if (*resolvedp) {
  2839. return true;
  2840. }
  2841. return ResolveSystemBinding(cx, obj, id, resolvedp);
  2842. }
  2843. bool
  2844. SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
  2845. {
  2846. bool ignored = false;
  2847. return EnumerateGlobal(cx, obj) &&
  2848. ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
  2849. }
  2850. template<decltype(JS::NewMapObject) Method>
  2851. bool
  2852. GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
  2853. size_t aSlotIndex,
  2854. JS::MutableHandle<JSObject*> aBackingObj,
  2855. bool* aBackingObjCreated)
  2856. {
  2857. JS::Rooted<JSObject*> reflector(aCx);
  2858. reflector = IsDOMObject(aObj) ? aObj : js::UncheckedUnwrap(aObj,
  2859. /* stopAtWindowProxy = */ false);
  2860. // Retrieve the backing object from the reserved slot on the maplike/setlike
  2861. // object. If it doesn't exist yet, create it.
  2862. JS::Rooted<JS::Value> slotValue(aCx);
  2863. slotValue = js::GetReservedSlot(reflector, aSlotIndex);
  2864. if (slotValue.isUndefined()) {
  2865. // Since backing object access can happen in non-originating compartments,
  2866. // make sure to create the backing object in reflector compartment.
  2867. {
  2868. JSAutoCompartment ac(aCx, reflector);
  2869. JS::Rooted<JSObject*> newBackingObj(aCx);
  2870. newBackingObj.set(Method(aCx));
  2871. if (NS_WARN_IF(!newBackingObj)) {
  2872. return false;
  2873. }
  2874. js::SetReservedSlot(reflector, aSlotIndex, JS::ObjectValue(*newBackingObj));
  2875. }
  2876. slotValue = js::GetReservedSlot(reflector, aSlotIndex);
  2877. *aBackingObjCreated = true;
  2878. } else {
  2879. *aBackingObjCreated = false;
  2880. }
  2881. if (!MaybeWrapNonDOMObjectValue(aCx, &slotValue)) {
  2882. return false;
  2883. }
  2884. aBackingObj.set(&slotValue.toObject());
  2885. return true;
  2886. }
  2887. bool
  2888. GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
  2889. size_t aSlotIndex,
  2890. JS::MutableHandle<JSObject*> aBackingObj,
  2891. bool* aBackingObjCreated)
  2892. {
  2893. return GetMaplikeSetlikeBackingObject<JS::NewMapObject>(aCx, aObj, aSlotIndex,
  2894. aBackingObj,
  2895. aBackingObjCreated);
  2896. }
  2897. bool
  2898. GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
  2899. size_t aSlotIndex,
  2900. JS::MutableHandle<JSObject*> aBackingObj,
  2901. bool* aBackingObjCreated)
  2902. {
  2903. return GetMaplikeSetlikeBackingObject<JS::NewSetObject>(aCx, aObj, aSlotIndex,
  2904. aBackingObj,
  2905. aBackingObjCreated);
  2906. }
  2907. bool
  2908. ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
  2909. {
  2910. JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
  2911. // Unpack callback and object from slots
  2912. JS::Rooted<JS::Value>
  2913. callbackFn(aCx, js::GetFunctionNativeReserved(&args.callee(),
  2914. FOREACH_CALLBACK_SLOT));
  2915. JS::Rooted<JS::Value>
  2916. maplikeOrSetlikeObj(aCx,
  2917. js::GetFunctionNativeReserved(&args.callee(),
  2918. FOREACH_MAPLIKEORSETLIKEOBJ_SLOT));
  2919. MOZ_ASSERT(aArgc == 3);
  2920. JS::AutoValueVector newArgs(aCx);
  2921. // Arguments are passed in as value, key, object. Keep value and key, replace
  2922. // object with the maplike/setlike object.
  2923. if (!newArgs.append(args.get(0))) {
  2924. return false;
  2925. }
  2926. if (!newArgs.append(args.get(1))) {
  2927. return false;
  2928. }
  2929. if (!newArgs.append(maplikeOrSetlikeObj)) {
  2930. return false;
  2931. }
  2932. JS::Rooted<JS::Value> rval(aCx, JS::UndefinedValue());
  2933. // Now actually call the user specified callback
  2934. return JS::Call(aCx, args.thisv(), callbackFn, newArgs, &rval);
  2935. }
  2936. static inline prototypes::ID
  2937. GetProtoIdForNewtarget(JS::Handle<JSObject*> aNewTarget)
  2938. {
  2939. const js::Class* newTargetClass = js::GetObjectClass(aNewTarget);
  2940. if (IsDOMIfaceAndProtoClass(newTargetClass)) {
  2941. const DOMIfaceAndProtoJSClass* newTargetIfaceClass =
  2942. DOMIfaceAndProtoJSClass::FromJSClass(newTargetClass);
  2943. if (newTargetIfaceClass->mType == eInterface) {
  2944. return newTargetIfaceClass->mPrototypeID;
  2945. }
  2946. } else if (JS_IsNativeFunction(aNewTarget, Constructor)) {
  2947. return GetNativePropertyHooksFromConstructorFunction(aNewTarget)->mPrototypeID;
  2948. }
  2949. return prototypes::id::_ID_Count;
  2950. }
  2951. bool
  2952. GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
  2953. JS::MutableHandle<JSObject*> aDesiredProto)
  2954. {
  2955. if (!aCallArgs.isConstructing()) {
  2956. aDesiredProto.set(nullptr);
  2957. return true;
  2958. }
  2959. // The desired prototype depends on the actual constructor that was invoked,
  2960. // which is passed to us as the newTarget in the callargs. We want to do
  2961. // something akin to the ES6 specification's GetProtototypeFromConstructor (so
  2962. // get .prototype on the newTarget, with a fallback to some sort of default).
  2963. // First, a fast path for the case when the the constructor is in fact one of
  2964. // our DOM constructors. This is safe because on those the "constructor"
  2965. // property is non-configurable and non-writable, so we don't have to do the
  2966. // slow JS_GetProperty call.
  2967. JS::Rooted<JSObject*> newTarget(aCx, &aCallArgs.newTarget().toObject());
  2968. JS::Rooted<JSObject*> originalNewTarget(aCx, newTarget);
  2969. // See whether we have a known DOM constructor here, such that we can take a
  2970. // fast path.
  2971. prototypes::ID protoID = GetProtoIdForNewtarget(newTarget);
  2972. if (protoID == prototypes::id::_ID_Count) {
  2973. // We might still have a cross-compartment wrapper for a known DOM
  2974. // constructor.
  2975. newTarget = js::CheckedUnwrap(newTarget);
  2976. if (newTarget && newTarget != originalNewTarget) {
  2977. protoID = GetProtoIdForNewtarget(newTarget);
  2978. }
  2979. }
  2980. if (protoID != prototypes::id::_ID_Count) {
  2981. ProtoAndIfaceCache& protoAndIfaceCache =
  2982. *GetProtoAndIfaceCache(js::GetGlobalForObjectCrossCompartment(newTarget));
  2983. aDesiredProto.set(protoAndIfaceCache.EntrySlotMustExist(protoID));
  2984. if (newTarget != originalNewTarget) {
  2985. return JS_WrapObject(aCx, aDesiredProto);
  2986. }
  2987. return true;
  2988. }
  2989. // Slow path. This basically duplicates the ES6 spec's
  2990. // GetPrototypeFromConstructor except that instead of taking a string naming
  2991. // the fallback prototype we just fall back to using null and assume that our
  2992. // caller will then pick the right default. The actual defaulting behavior
  2993. // here still needs to be defined in the Web IDL specification.
  2994. //
  2995. // Note that it's very important to do this property get on originalNewTarget,
  2996. // not our unwrapped newTarget, since we want to get Xray behavior here as
  2997. // needed.
  2998. // XXXbz for speed purposes, using a preinterned id here sure would be nice.
  2999. JS::Rooted<JS::Value> protoVal(aCx);
  3000. if (!JS_GetProperty(aCx, originalNewTarget, "prototype", &protoVal)) {
  3001. return false;
  3002. }
  3003. if (!protoVal.isObject()) {
  3004. aDesiredProto.set(nullptr);
  3005. return true;
  3006. }
  3007. aDesiredProto.set(&protoVal.toObject());
  3008. return true;
  3009. }
  3010. // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
  3011. already_AddRefed<nsGenericHTMLElement>
  3012. CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
  3013. JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv)
  3014. {
  3015. // Step 1.
  3016. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
  3017. if (!window) {
  3018. aRv.Throw(NS_ERROR_UNEXPECTED);
  3019. return nullptr;
  3020. }
  3021. nsIDocument* doc = window->GetExtantDoc();
  3022. if (!doc) {
  3023. aRv.Throw(NS_ERROR_UNEXPECTED);
  3024. return nullptr;
  3025. }
  3026. RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements());
  3027. if (!registry) {
  3028. aRv.Throw(NS_ERROR_UNEXPECTED);
  3029. return nullptr;
  3030. }
  3031. // Step 2 is in the code output by CGClassConstructor.
  3032. // Step 3.
  3033. JSContext* cx = aGlobal.Context();
  3034. JS::Rooted<JSObject*> newTarget(cx, &aCallArgs.newTarget().toObject());
  3035. CustomElementDefinition* definition =
  3036. registry->LookupCustomElementDefinition(cx, newTarget);
  3037. if (!definition) {
  3038. aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
  3039. return nullptr;
  3040. }
  3041. // The callee might be an Xray. Unwrap it to get actual callee.
  3042. JS::Rooted<JSObject*> callee(cx, js::CheckedUnwrap(&aCallArgs.callee()));
  3043. if (!callee) {
  3044. aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  3045. return nullptr;
  3046. }
  3047. // And the actual callee might be in different compartment, so enter its
  3048. // compartment before getting the standard constructor object to compare to,
  3049. // so we get it from the same global as callee itself.
  3050. JSAutoCompartment ac(cx, callee);
  3051. int32_t tag = eHTMLTag_userdefined;
  3052. if (!definition->IsCustomBuiltIn()) {
  3053. // Step 4.
  3054. // If the definition is for an autonomous custom element, the active
  3055. // function should be HTMLElement.
  3056. JS::Rooted<JSObject*> constructor(cx, HTMLElementBinding::GetConstructorObject(cx));
  3057. if (!constructor) {
  3058. aRv.NoteJSContextException(cx);
  3059. return nullptr;
  3060. }
  3061. if (callee != constructor) {
  3062. aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
  3063. return nullptr;
  3064. }
  3065. } else {
  3066. // Step 5.
  3067. // If the definition is for a customized built-in element, the localName
  3068. // should be defined in the specification.
  3069. tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
  3070. if (tag == eHTMLTag_userdefined) {
  3071. aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
  3072. return nullptr;
  3073. }
  3074. MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
  3075. // If the definition is for a customized built-in element, the active
  3076. // function should be the localname's element interface.
  3077. constructorGetterCallback cb = sConstructorGetterCallback[tag];
  3078. if (!cb) {
  3079. aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
  3080. return nullptr;
  3081. }
  3082. JS::Rooted<JSObject*> constructor(cx, cb(cx));
  3083. if (!constructor) {
  3084. aRv.NoteJSContextException(cx);
  3085. return nullptr;
  3086. }
  3087. if (callee != constructor) {
  3088. aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
  3089. return nullptr;
  3090. }
  3091. }
  3092. RefPtr<mozilla::dom::NodeInfo> nodeInfo =
  3093. doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
  3094. nullptr,
  3095. kNameSpaceID_XHTML,
  3096. nsIDOMNode::ELEMENT_NODE);
  3097. if (!nodeInfo) {
  3098. aRv.Throw(NS_ERROR_UNEXPECTED);
  3099. return nullptr;
  3100. }
  3101. // Step 6 and Step 7 are in the code output by CGClassConstructor.
  3102. // Step 8.
  3103. nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
  3104. definition->mConstructionStack;
  3105. if (constructionStack.IsEmpty()) {
  3106. RefPtr<nsGenericHTMLElement> newElement;
  3107. if (tag == eHTMLTag_userdefined) {
  3108. // Autonomous custom element.
  3109. newElement = NS_NewHTMLElement(nodeInfo.forget());
  3110. } else {
  3111. // Customized built-in element.
  3112. newElement = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
  3113. }
  3114. newElement->SetCustomElementData(
  3115. new CustomElementData(definition->mType, CustomElementData::State::eCustom));
  3116. newElement->SetCustomElementDefinition(definition);
  3117. return newElement.forget();
  3118. }
  3119. // Step 9.
  3120. RefPtr<nsGenericHTMLElement>& element = constructionStack.LastElement();
  3121. // Step 10.
  3122. if (element == ALEADY_CONSTRUCTED_MARKER) {
  3123. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  3124. return nullptr;
  3125. }
  3126. // Step 11.
  3127. // Do prototype swizzling for upgrading a custom element here, for cases when
  3128. // we have a reflector already. If we don't have one yet, our caller will
  3129. // create it with the right proto (by calling DoGetOrCreateDOMReflector with
  3130. // that proto).
  3131. JS::Rooted<JSObject*> reflector(cx, element->GetWrapper());
  3132. if (reflector) {
  3133. // reflector might be in different compartment.
  3134. JSAutoCompartment ac(cx, reflector);
  3135. JS::Rooted<JSObject*> givenProto(cx, aGivenProto);
  3136. if (!JS_WrapObject(cx, &givenProto) ||
  3137. !JS_SetPrototype(cx, reflector, givenProto)) {
  3138. aRv.NoteJSContextException(cx);
  3139. return nullptr;
  3140. }
  3141. }
  3142. // Step 12 and Step 13.
  3143. return element.forget();
  3144. }
  3145. #ifdef DEBUG
  3146. namespace binding_detail {
  3147. void
  3148. AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
  3149. JS::Handle<JSObject*> aGivenProto)
  3150. {
  3151. if (!aGivenProto) {
  3152. // Nothing to assert here
  3153. return;
  3154. }
  3155. JS::Rooted<JSObject*> reflector(aCx, aReflector);
  3156. JSAutoCompartment ac(aCx, reflector);
  3157. JS::Rooted<JSObject*> reflectorProto(aCx);
  3158. bool ok = JS_GetPrototype(aCx, reflector, &reflectorProto);
  3159. MOZ_ASSERT(ok);
  3160. // aGivenProto may not be in the right compartment here, so we
  3161. // have to wrap it to compare.
  3162. JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
  3163. ok = JS_WrapObject(aCx, &givenProto);
  3164. MOZ_ASSERT(ok);
  3165. MOZ_ASSERT(givenProto == reflectorProto,
  3166. "How are we supposed to change the proto now?");
  3167. }
  3168. } // namespace binding_detail
  3169. #endif // DEBUG
  3170. void
  3171. SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
  3172. UseCounter aUseCounter)
  3173. {
  3174. nsGlobalWindow* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
  3175. if (win && win->GetDocument()) {
  3176. win->GetDocument()->SetDocumentAndPageUseCounter(aUseCounter);
  3177. }
  3178. }
  3179. namespace {
  3180. // This runnable is used to write a deprecation message from a worker to the
  3181. // console running on the main-thread.
  3182. class DeprecationWarningRunnable final : public WorkerProxyToMainThreadRunnable
  3183. {
  3184. nsIDocument::DeprecatedOperations mOperation;
  3185. public:
  3186. DeprecationWarningRunnable(WorkerPrivate* aWorkerPrivate,
  3187. nsIDocument::DeprecatedOperations aOperation)
  3188. : WorkerProxyToMainThreadRunnable(aWorkerPrivate)
  3189. , mOperation(aOperation)
  3190. {
  3191. MOZ_ASSERT(aWorkerPrivate);
  3192. aWorkerPrivate->AssertIsOnWorkerThread();
  3193. }
  3194. private:
  3195. void
  3196. RunOnMainThread() override
  3197. {
  3198. MOZ_ASSERT(NS_IsMainThread());
  3199. // Walk up to our containing page
  3200. WorkerPrivate* wp = mWorkerPrivate;
  3201. while (wp->GetParent()) {
  3202. wp = wp->GetParent();
  3203. }
  3204. nsPIDOMWindowInner* window = wp->GetWindow();
  3205. if (window && window->GetExtantDoc()) {
  3206. window->GetExtantDoc()->WarnOnceAbout(mOperation);
  3207. }
  3208. }
  3209. void
  3210. RunBackOnWorkerThread() override
  3211. {}
  3212. };
  3213. } // anonymous namespace
  3214. void
  3215. DeprecationWarning(JSContext* aCx, JSObject* aObject,
  3216. nsIDocument::DeprecatedOperations aOperation)
  3217. {
  3218. GlobalObject global(aCx, aObject);
  3219. if (global.Failed()) {
  3220. NS_ERROR("Could not create global for DeprecationWarning");
  3221. return;
  3222. }
  3223. if (NS_IsMainThread()) {
  3224. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
  3225. if (window && window->GetExtantDoc()) {
  3226. window->GetExtantDoc()->WarnOnceAbout(aOperation);
  3227. }
  3228. return;
  3229. }
  3230. WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
  3231. if (!workerPrivate) {
  3232. return;
  3233. }
  3234. RefPtr<DeprecationWarningRunnable> runnable =
  3235. new DeprecationWarningRunnable(workerPrivate, aOperation);
  3236. runnable->Dispatch();
  3237. }
  3238. namespace binding_detail {
  3239. JSObject*
  3240. UnprivilegedJunkScopeOrWorkerGlobal()
  3241. {
  3242. if (NS_IsMainThread()) {
  3243. return xpc::UnprivilegedJunkScope();
  3244. }
  3245. return GetCurrentThreadWorkerGlobal();
  3246. }
  3247. } // namespace binding_detail
  3248. } // namespace dom
  3249. } // namespace mozilla