/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*//* vim: set ts=2 sw=2 et tw=79: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */#include"BindingUtils.h"#include<algorithm>#include<stdarg.h>#include"JavaScriptParent.h"#include"mozilla/DebugOnly.h"#include"mozilla/FloatingPoint.h"#include"mozilla/Assertions.h"#include"AccessCheck.h"#include"jsfriendapi.h"#include"js/OldDebugAPI.h"#include"nsContentUtils.h"#include"nsIDOMGlobalPropertyInitializer.h"#include"nsIPrincipal.h"#include"nsIXPConnect.h"#include"WrapperFactory.h"#include"xpcprivate.h"#include"XPCQuickStubs.h"#include"XrayWrapper.h"#include"nsPrintfCString.h"#include"prprf.h"#include"mozilla/dom/ScriptSettings.h"#include"mozilla/dom/DOMError.h"#include"mozilla/dom/DOMErrorBinding.h"#include"mozilla/dom/HTMLObjectElement.h"#include"mozilla/dom/HTMLObjectElementBinding.h"#include"mozilla/dom/HTMLSharedObjectElement.h"#include"mozilla/dom/HTMLEmbedElementBinding.h"#include"mozilla/dom/HTMLAppletElementBinding.h"#include"mozilla/dom/Promise.h"#include"WorkerPrivate.h"namespacemozilla{namespacedom{JSErrorFormatStringErrorFormatString[]={#define MSG_DEF(_name, _argc, _str) \ { _str, _argc, JSEXN_TYPEERR },#include"mozilla/dom/Errors.msg"#undef MSG_DEF};constJSErrorFormatString*GetErrorMessage(void*aUserRef,constchar*aLocale,constunsignedaErrorNumber){MOZ_ASSERT(aErrorNumber<ArrayLength(ErrorFormatString));return&ErrorFormatString[aErrorNumber];}boolThrowErrorMessage(JSContext*aCx,constErrNumaErrorNumber,...){va_listap;va_start(ap,aErrorNumber);JS_ReportErrorNumberVA(aCx,GetErrorMessage,nullptr,static_cast<constunsigned>(aErrorNumber),ap);va_end(ap);returnfalse;}boolThrowInvalidThis(JSContext*aCx,constJS::CallArgs&aArgs,constErrNumaErrorNumber,constchar*aInterfaceName){NS_ConvertASCIItoUTF16ifaceName(aInterfaceName);// This should only be called for DOM methods/getters/setters, which// are JSNative-backed functions, so we can assume that// JS_ValueToFunction and JS_GetFunctionDisplayId will both return// non-null and that JS_GetStringCharsZ returns non-null.JS::Rooted<JSFunction*>func(aCx,JS_ValueToFunction(aCx,aArgs.calleev()));MOZ_ASSERT(func);JS::Rooted<JSString*>funcName(aCx,JS_GetFunctionDisplayId(func));MOZ_ASSERT(funcName);JS_ReportErrorNumberUC(aCx,GetErrorMessage,nullptr,static_cast<constunsigned>(aErrorNumber),JS_GetStringCharsZ(aCx,funcName),ifaceName.get());returnfalse;}boolThrowInvalidThis(JSContext*aCx,constJS::CallArgs&aArgs,constErrNumaErrorNumber,prototypes::IDaProtoId){returnThrowInvalidThis(aCx,aArgs,aErrorNumber,NamesOfInterfacesWithProtos(aProtoId));}boolThrowNoSetterArg(JSContext*aCx,prototypes::IDaProtoId){nsPrintfCStringerrorMessage("%s attribute setter",NamesOfInterfacesWithProtos(aProtoId));returnThrowErrorMessage(aCx,MSG_MISSING_ARGUMENTS,errorMessage.get());}}// namespace domstructErrorResult::Message{nsTArray<nsString>mArgs;dom::ErrNummErrorNumber;};voidErrorResult::ThrowTypeError(constdom::ErrNumerrorNumber,...){va_listap;va_start(ap,errorNumber);if(IsJSException()){// We have rooted our mJSException, and we don't have the info// needed to unroot here, so just bail.va_end(ap);MOZ_ASSERT(false,"Ignoring ThrowTypeError call because we have a JS exception");return;}if(IsTypeError()){deletemMessage;}mResult=NS_ERROR_TYPE_ERR;Message*message=newMessage();message->mErrorNumber=errorNumber;uint16_targCount=dom::GetErrorMessage(nullptr,nullptr,errorNumber)->argCount;MOZ_ASSERT(argCount<=10);argCount=std::min<uint16_t>(argCount,10);while(argCount--){message->mArgs.AppendElement(*va_arg(ap,nsString*));}mMessage=message;va_end(ap);}voidErrorResult::ReportTypeError(JSContext*aCx){MOZ_ASSERT(mMessage,"ReportTypeError() can be called only once");Message*message=mMessage;constuint32_targCount=message->mArgs.Length();constjschar*args[11];for(uint32_ti=0;i<argCount;++i){args[i]=message->mArgs.ElementAt(i).get();}args[argCount]=nullptr;JS_ReportErrorNumberUCArray(aCx,dom::GetErrorMessage,nullptr,static_cast<constunsigned>(message->mErrorNumber),argCount>0?args:nullptr);ClearMessage();}voidErrorResult::ClearMessage(){if(IsTypeError()){deletemMessage;mMessage=nullptr;}}voidErrorResult::ThrowJSException(JSContext*cx,JS::Handle<JS::Value>exn){MOZ_ASSERT(mMightHaveUnreportedJSException,"Why didn't you tell us you planned to throw a JS exception?");if(IsTypeError()){deletemMessage;}// Make sure mJSException is initialized _before_ we try to root it. But// don't set it to exn yet, because we don't want to do that until after we// root.mJSException=JS::UndefinedValue();if(!js::AddRawValueRoot(cx,&mJSException,"ErrorResult::mJSException")){// Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have// in fact rooted mJSException.mResult=NS_ERROR_OUT_OF_MEMORY;}else{mJSException=exn;mResult=NS_ERROR_DOM_JS_EXCEPTION;}}voidErrorResult::ReportJSException(JSContext*cx){MOZ_ASSERT(!mMightHaveUnreportedJSException,"Why didn't you tell us you planned to handle JS exceptions?");JS::Rooted<JS::Value>exception(cx,mJSException);if(JS_WrapValue(cx,&exception)){JS_SetPendingException(cx,exception);}mJSException=exception;// If JS_WrapValue failed, not much we can do about it... No matter// what, go ahead and unroot mJSException.js::RemoveRawValueRoot(cx,&mJSException);}voidErrorResult::ReportJSExceptionFromJSImplementation(JSContext*aCx){MOZ_ASSERT(!mMightHaveUnreportedJSException,"Why didn't you tell us you planned to handle JS exceptions?");dom::DOMError*domError;nsresultrv=UNWRAP_OBJECT(DOMError,&mJSException.toObject(),domError);if(NS_FAILED(rv)){// Unwrapping really shouldn't fail here, if mExceptionHandling is set to// eRethrowContentExceptions then the CallSetup destructor only stores an// exception if it unwraps to DOMError. If we reach this then either// mExceptionHandling wasn't set to eRethrowContentExceptions and we// shouldn't be calling ReportJSExceptionFromJSImplementation or something// went really wrong.NS_RUNTIMEABORT("We stored a non-DOMError exception!");}nsStringmessage;domError->GetMessage(message);JS_ReportError(aCx,"%hs",message.get());js::RemoveRawValueRoot(aCx,&mJSException);// We no longer have a useful exception but we do want to signal that an error// occured.mResult=NS_ERROR_FAILURE;}voidErrorResult::StealJSException(JSContext*cx,JS::MutableHandle<JS::Value>value){MOZ_ASSERT(!mMightHaveUnreportedJSException,"Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException");MOZ_ASSERT(IsJSException(),"No exception to steal");value.set(mJSException);js::RemoveRawValueRoot(cx,&mJSException);mResult=NS_OK;}voidErrorResult::ReportNotEnoughArgsError(JSContext*cx,constchar*ifaceName,constchar*memberName){MOZ_ASSERT(ErrorCode()==NS_ERROR_XPC_NOT_ENOUGH_ARGS);nsPrintfCStringerrorMessage("%s.%s",ifaceName,memberName);ThrowErrorMessage(cx,dom::MSG_MISSING_ARGUMENTS,errorMessage.get());}namespacedom{boolDefineConstants(JSContext*cx,JS::Handle<JSObject*>obj,constConstantSpec*cs){JS::Rooted<JS::Value>value(cx);for(;cs->name;++cs){value=cs->value;boolok=JS_DefineProperty(cx,obj,cs->name,value,JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);if(!ok){returnfalse;}}returntrue;}staticinlineboolDefine(JSContext*cx,JS::Handle<JSObject*>obj,constJSFunctionSpec*spec){returnJS_DefineFunctions(cx,obj,spec);}staticinlineboolDefine(JSContext*cx,JS::Handle<JSObject*>obj,constJSPropertySpec*spec){returnJS_DefineProperties(cx,obj,spec);}staticinlineboolDefine(JSContext*cx,JS::Handle<JSObject*>obj,constConstantSpec*spec){returnDefineConstants(cx,obj,spec);}template<typenameT>boolDefinePrefable(JSContext*cx,JS::Handle<JSObject*>obj,constPrefable<T>*props){MOZ_ASSERT(props);MOZ_ASSERT(props->specs);do{// Define if enabledif(props->isEnabled(cx,obj)){if(!Define(cx,obj,props->specs)){returnfalse;}}}while((++props)->specs);returntrue;}boolDefineUnforgeableAttributes(JSContext*cx,JS::Handle<JSObject*>obj,constPrefable<constJSPropertySpec>*props){returnDefinePrefable(cx,obj,props);}// We should use JSFunction objects for interface objects, but we need a custom// hasInstance hook because we have new interface objects on prototype chains of// old (XPConnect-based) bindings. Because Function.prototype.toString throws if// passed a non-Function object we also need to provide our own toString method// for interface objects.enum{TOSTRING_CLASS_RESERVED_SLOT=0,TOSTRING_NAME_RESERVED_SLOT=1};staticboolInterfaceObjectToString(JSContext*cx,unsignedargc,JS::Value*vp){JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);JS::Rooted<JSObject*>callee(cx,&args.callee());if(!args.thisv().isObject()){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_CANT_CONVERT_TO,"null","object");returnfalse;}JS::Valuev=js::GetFunctionNativeReserved(callee,TOSTRING_CLASS_RESERVED_SLOT);constJSClass*clasp=static_cast<constJSClass*>(v.toPrivate());v=js::GetFunctionNativeReserved(callee,TOSTRING_NAME_RESERVED_SLOT);JSString*jsname=static_cast<JSString*>(v.toString());size_tlength;constjschar*name=JS_GetInternedStringCharsAndLength(jsname,&length);if(js::GetObjectJSClass(&args.thisv().toObject())!=clasp){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_INCOMPATIBLE_PROTO,NS_ConvertUTF16toUTF8(name).get(),"toString","object");returnfalse;}nsStringstr;str.AppendLiteral("function ");str.Append(name,length);str.AppendLiteral("() {");str.Append('\n');str.AppendLiteral(" [native code]");str.Append('\n');str.AppendLiteral("}");returnxpc::NonVoidStringToJsval(cx,str,args.rval());}boolConstructor(JSContext*cx,unsignedargc,JS::Value*vp){JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);constJS::Value&v=js::GetFunctionNativeReserved(&args.callee(),CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);constJSNativeHolder*nativeHolder=static_cast<constJSNativeHolder*>(v.toPrivate());return(nativeHolder->mNative)(cx,argc,vp);}staticJSObject*CreateConstructor(JSContext*cx,JS::Handle<JSObject*>global,constchar*name,constJSNativeHolder*nativeHolder,unsignedctorNargs){JSFunction*fun=js::NewFunctionWithReserved(cx,Constructor,ctorNargs,JSFUN_CONSTRUCTOR,global,name);if(!fun){returnnullptr;}JSObject*constructor=JS_GetFunctionObject(fun);js::SetFunctionNativeReserved(constructor,CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));returnconstructor;}staticboolDefineConstructor(JSContext*cx,JS::Handle<JSObject*>global,constchar*name,JS::Handle<JSObject*>constructor){boolalreadyDefined;if(!JS_AlreadyHasOwnProperty(cx,global,name,&alreadyDefined)){returnfalse;}// This is Enumerable: False per spec.returnalreadyDefined||JS_DefineProperty(cx,global,name,constructor,0);}staticJSObject*CreateInterfaceObject(JSContext*cx,JS::Handle<JSObject*>global,JS::Handle<JSObject*>constructorProto,constJSClass*constructorClass,constJSNativeHolder*constructorNative,unsignedctorNargs,constNamedConstructor*namedConstructors,JS::Handle<JSObject*>proto,constNativeProperties*properties,constNativeProperties*chromeOnlyProperties,constchar*name,booldefineOnGlobal){JS::Rooted<JSObject*>constructor(cx);if(constructorClass){MOZ_ASSERT(constructorProto);constructor=JS_NewObject(cx,constructorClass,constructorProto,global);}else{MOZ_ASSERT(constructorNative);MOZ_ASSERT(constructorProto==JS_GetFunctionPrototype(cx,global));constructor=CreateConstructor(cx,global,name,constructorNative,ctorNargs);}if(!constructor){returnnullptr;}if(constructorClass){// Have to shadow Function.prototype.toString, since that throws// on things that are not js::FunctionClass.JS::Rooted<JSFunction*>toString(cx,js::DefineFunctionWithReserved(cx,constructor,"toString",InterfaceObjectToString,0,0));if(!toString){returnnullptr;}JSString*str=::JS_InternString(cx,name);if(!str){returnnullptr;}JSObject*toStringObj=JS_GetFunctionObject(toString);js::SetFunctionNativeReserved(toStringObj,TOSTRING_CLASS_RESERVED_SLOT,PRIVATE_TO_JSVAL(const_cast<JSClass*>(constructorClass)));js::SetFunctionNativeReserved(toStringObj,TOSTRING_NAME_RESERVED_SLOT,STRING_TO_JSVAL(str));if(!JS_DefineProperty(cx,constructor,"length",ctorNargs,JSPROP_READONLY|JSPROP_PERMANENT)){returnnullptr;}}if(properties){if(properties->staticMethods&&!DefinePrefable(cx,constructor,properties->staticMethods)){returnnullptr;}if(properties->staticAttributes&&!DefinePrefable(cx,constructor,properties->staticAttributes)){returnnullptr;}if(properties->constants&&!DefinePrefable(cx,constructor,properties->constants)){returnnullptr;}}if(chromeOnlyProperties){if(chromeOnlyProperties->staticMethods&&!DefinePrefable(cx,constructor,chromeOnlyProperties->staticMethods)){returnnullptr;}if(chromeOnlyProperties->staticAttributes&&!DefinePrefable(cx,constructor,chromeOnlyProperties->staticAttributes)){returnnullptr;}if(chromeOnlyProperties->constants&&!DefinePrefable(cx,constructor,chromeOnlyProperties->constants)){returnnullptr;}}if(proto&&!JS_LinkConstructorAndPrototype(cx,constructor,proto)){returnnullptr;}if(defineOnGlobal&&!DefineConstructor(cx,global,name,constructor)){returnnullptr;}if(namedConstructors){intnamedConstructorSlot=DOM_INTERFACE_SLOTS_BASE;while(namedConstructors->mName){JS::Rooted<JSObject*>namedConstructor(cx,CreateConstructor(cx,global,namedConstructors->mName,&namedConstructors->mHolder,namedConstructors->mNargs));if(!namedConstructor||!JS_DefineProperty(cx,namedConstructor,"prototype",proto,JSPROP_PERMANENT|JSPROP_READONLY,JS_PropertyStub,JS_StrictPropertyStub)||(defineOnGlobal&&!DefineConstructor(cx,global,namedConstructors->mName,namedConstructor))){returnnullptr;}js::SetReservedSlot(constructor,namedConstructorSlot++,JS::ObjectValue(*namedConstructor));++namedConstructors;}}returnconstructor;}boolDefineWebIDLBindingPropertiesOnXPCObject(JSContext*cx,JS::Handle<JSObject*>obj,constNativeProperties*properties,booldefineUnforgeableAttributes){if(properties->methods&&!DefinePrefable(cx,obj,properties->methods)){returnfalse;}if(properties->attributes&&!DefinePrefable(cx,obj,properties->attributes)){returnfalse;}if(defineUnforgeableAttributes&&properties->unforgeableAttributes&&!DefinePrefable(cx,obj,properties->unforgeableAttributes)){returnfalse;}returntrue;}staticJSObject*CreateInterfacePrototypeObject(JSContext*cx,JS::Handle<JSObject*>global,JS::Handle<JSObject*>parentProto,constJSClass*protoClass,constNativeProperties*properties,constNativeProperties*chromeOnlyProperties){JS::Rooted<JSObject*>ourProto(cx,JS_NewObjectWithUniqueType(cx,protoClass,parentProto,global));if(!ourProto||!DefineProperties(cx,ourProto,properties,chromeOnlyProperties)){returnnullptr;}returnourProto;}boolDefineProperties(JSContext*cx,JS::Handle<JSObject*>obj,constNativeProperties*properties,constNativeProperties*chromeOnlyProperties){if(properties){if(properties->methods&&!DefinePrefable(cx,obj,properties->methods)){returnfalse;}if(properties->attributes&&!DefinePrefable(cx,obj,properties->attributes)){returnfalse;}if(properties->constants&&!DefinePrefable(cx,obj,properties->constants)){returnfalse;}}if(chromeOnlyProperties){if(chromeOnlyProperties->methods&&!DefinePrefable(cx,obj,chromeOnlyProperties->methods)){returnfalse;}if(chromeOnlyProperties->attributes&&!DefinePrefable(cx,obj,chromeOnlyProperties->attributes)){returnfalse;}if(chromeOnlyProperties->constants&&!DefinePrefable(cx,obj,chromeOnlyProperties->constants)){returnfalse;}}returntrue;}voidCreateInterfaceObjects(JSContext*cx,JS::Handle<JSObject*>global,JS::Handle<JSObject*>protoProto,constJSClass*protoClass,JS::Heap<JSObject*>*protoCache,JS::Handle<JSObject*>constructorProto,constJSClass*constructorClass,constJSNativeHolder*constructor,unsignedctorNargs,constNamedConstructor*namedConstructors,JS::Heap<JSObject*>*constructorCache,constDOMClass*domClass,constNativeProperties*properties,constNativeProperties*chromeOnlyProperties,constchar*name,booldefineOnGlobal){MOZ_ASSERT(protoClass||constructorClass||constructor,"Need at least one class or a constructor!");MOZ_ASSERT(!((properties&&(properties->methods||properties->attributes))||(chromeOnlyProperties&&(chromeOnlyProperties->methods||chromeOnlyProperties->attributes)))||protoClass,"Methods or properties but no protoClass!");MOZ_ASSERT(!((properties&&(properties->staticMethods||properties->staticAttributes))||(chromeOnlyProperties&&(chromeOnlyProperties->staticMethods||chromeOnlyProperties->staticAttributes)))||constructorClass||constructor,"Static methods but no constructorClass or constructor!");MOZ_ASSERT(bool(name)==bool(constructorClass||constructor),"Must have name precisely when we have an interface object");MOZ_ASSERT(!constructorClass||!constructor);MOZ_ASSERT(!protoClass==!protoCache,"If, and only if, there is an interface prototype object we need ""to cache it");MOZ_ASSERT(!(constructorClass||constructor)==!constructorCache,"If, and only if, there is an interface object we need to cache ""it");JS::Rooted<JSObject*>proto(cx);if(protoClass){proto=CreateInterfacePrototypeObject(cx,global,protoProto,protoClass,properties,chromeOnlyProperties);if(!proto){return;}js::SetReservedSlot(proto,DOM_PROTO_INSTANCE_CLASS_SLOT,JS::PrivateValue(const_cast<DOMClass*>(domClass)));*protoCache=proto;}else{MOZ_ASSERT(!proto);}JSObject*interface;if(constructorClass||constructor){interface=CreateInterfaceObject(cx,global,constructorProto,constructorClass,constructor,ctorNargs,namedConstructors,proto,properties,chromeOnlyProperties,name,defineOnGlobal);if(!interface){if(protoCache){// If we fail we need to make sure to clear the value of protoCache we// set above.*protoCache=nullptr;}return;}*constructorCache=interface;}}boolNativeInterface2JSObjectAndThrowIfFailed(JSContext*aCx,JS::Handle<JSObject*>aScope,JS::MutableHandle<JS::Value>aRetval,xpcObjectHelper&aHelper,constnsIID*aIID,boolaAllowNativeWrapper){js::AssertSameCompartment(aCx,aScope);nsresultrv;// Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need// on all threads.nsWrapperCache*cache=aHelper.GetWrapperCache();if(cache&&cache->IsDOMBinding()){JS::Rooted<JSObject*>obj(aCx,cache->GetWrapper());if(!obj){obj=cache->WrapObject(aCx);}if(obj&&aAllowNativeWrapper&&!JS_WrapObject(aCx,&obj)){returnfalse;}if(obj){aRetval.setObject(*obj);returntrue;}}MOZ_ASSERT(NS_IsMainThread());if(!XPCConvert::NativeInterface2JSObject(aRetval,nullptr,aHelper,aIID,nullptr,aAllowNativeWrapper,&rv)){// I can't tell if NativeInterface2JSObject throws JS exceptions// or not. This is a sloppy stab at the right semantics; the// method really ought to be fixed to behave consistently.if(!JS_IsExceptionPending(aCx)){Throw(aCx,NS_FAILED(rv)?rv:NS_ERROR_UNEXPECTED);}returnfalse;}returntrue;}boolTryPreserveWrapper(JSObject*obj){MOZ_ASSERT(IsDOMObject(obj));if(nsISupports*native=UnwrapDOMObjectToISupports(obj)){nsWrapperCache*cache=nullptr;CallQueryInterface(native,&cache);if(cache){cache->PreserveWrapper(native);}returntrue;}// If this DOMClass is not cycle collected, then it isn't wrappercached,// so it does not need to be preserved. If it is cycle collected, then// we can't tell if it is wrappercached or not, so we just return false.constDOMClass*domClass=GetDOMClass(obj);returndomClass&&!domClass->mParticipant;}// Can only be called with the immediate prototype of the instance object. Can// only be called on the prototype of an object known to be a DOM instance.boolInstanceClassHasProtoAtDepth(JSObject*protoObject,uint32_tprotoID,uint32_tdepth){constDOMClass*domClass=static_cast<constDOMClass*>(js::GetReservedSlot(protoObject,DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate());return(uint32_t)domClass->mInterfaceChain[depth]==protoID;}// Only set allowNativeWrapper to false if you really know you need it, if in// doubt use true. Setting it to false disables security wrappers.boolXPCOMObjectToJsval(JSContext*cx,JS::Handle<JSObject*>scope,xpcObjectHelper&helper,constnsIID*iid,boolallowNativeWrapper,JS::MutableHandle<JS::Value>rval){if(!NativeInterface2JSObjectAndThrowIfFailed(cx,scope,rval,helper,iid,allowNativeWrapper)){returnfalse;}#ifdef DEBUGJSObject*jsobj=rval.toObjectOrNull();if(jsobj&&!js::GetObjectParent(jsobj))NS_ASSERTION(js::GetObjectClass(jsobj)->flags&JSCLASS_IS_GLOBAL,"Why did we recreate this wrapper?");#endifreturntrue;}boolVariantToJsval(JSContext*aCx,nsIVariant*aVariant,JS::MutableHandle<JS::Value>aRetval){nsresultrv;if(!XPCVariant::VariantDataToJS(aVariant,&rv,aRetval)){// Does it throw? Who knowsif(!JS_IsExceptionPending(aCx)){Throw(aCx,NS_FAILED(rv)?rv:NS_ERROR_UNEXPECTED);}returnfalse;}returntrue;}boolQueryInterface(JSContext*cx,unsignedargc,JS::Value*vp){JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);JS::Rooted<JS::Value>thisv(cx,JS_THIS(cx,vp));if(thisv.isNull())returnfalse;// Get the object. It might be a security wrapper, in which case we do a checked// unwrap.JS::Rooted<JSObject*>origObj(cx,&thisv.toObject());JSObject*obj=js::CheckedUnwrap(origObj,/* stopAtOuter = */false);if(!obj){JS_ReportError(cx,"Permission denied to access object");returnfalse;}// Switch this to UnwrapDOMObjectToISupports once our global objects are// using new bindings.JS::Rooted<JS::Value>val(cx,JS::ObjectValue(*obj));nsISupports*native=nullptr;nsCOMPtr<nsISupports>nativeRef;xpc_qsUnwrapArg<nsISupports>(cx,val,&native,static_cast<nsISupports**>(getter_AddRefs(nativeRef)),&val);if(!native){returnThrow(cx,NS_ERROR_FAILURE);}if(argc<1){returnThrow(cx,NS_ERROR_XPC_NOT_ENOUGH_ARGS);}if(!args[0].isObject()){returnThrow(cx,NS_ERROR_XPC_BAD_CONVERT_JS);}nsIJSID*iid;SelfRefiidRef;if(NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx,args[0],&iid,&iidRef.ptr,args[0]))){returnThrow(cx,NS_ERROR_XPC_BAD_CONVERT_JS);}MOZ_ASSERT(iid);if(iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))){nsresultrv;nsCOMPtr<nsIClassInfo>ci=do_QueryInterface(native,&rv);if(NS_FAILED(rv)){returnThrow(cx,rv);}returnWrapObject(cx,ci,&NS_GET_IID(nsIClassInfo),args.rval());}nsCOMPtr<nsISupports>unused;nsresultrv=native->QueryInterface(*iid->GetID(),getter_AddRefs(unused));if(NS_FAILED(rv)){returnThrow(cx,rv);}*vp=thisv;returntrue;}JS::ValueGetInterfaceImpl(JSContext*aCx,nsIInterfaceRequestor*aRequestor,nsWrapperCache*aCache,nsIJSID*aIID,ErrorResult&aError){constnsID*iid=aIID->GetID();nsRefPtr<nsISupports>result;aError=aRequestor->GetInterface(*iid,getter_AddRefs(result));if(aError.Failed()){returnJS::NullValue();}JS::Rooted<JS::Value>v(aCx,JSVAL_NULL);if(!WrapObject(aCx,result,iid,&v)){aError.Throw(NS_ERROR_FAILURE);returnJS::NullValue();}returnv;}boolThrowingConstructor(JSContext*cx,unsignedargc,JS::Value*vp){returnThrowErrorMessage(cx,MSG_ILLEGAL_CONSTRUCTOR);}boolThrowConstructorWithoutNew(JSContext*cx,constchar*name){returnThrowErrorMessage(cx,MSG_CONSTRUCTOR_WITHOUT_NEW,name);}inlineconstNativePropertyHooks*GetNativePropertyHooks(JSContext*cx,JS::Handle<JSObject*>obj,DOMObjectType&type,bool&isGlobal){constjs::Class*clasp=js::GetObjectClass(obj);isGlobal=(clasp->flags&JSCLASS_DOM_GLOBAL)!=0;constDOMClass*domClass=GetDOMClass(clasp);if(domClass){type=eInstance;returndomClass->mNativeHooks;}if(JS_ObjectIsFunction(cx,obj)){MOZ_ASSERT(JS_IsNativeFunction(obj,Constructor));type=eInterface;constJS::Value&v=js::GetFunctionNativeReserved(obj,CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);constJSNativeHolder*nativeHolder=static_cast<constJSNativeHolder*>(v.toPrivate());returnnativeHolder->mPropertyHooks;}MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));constDOMIfaceAndProtoJSClass*ifaceAndProtoJSClass=DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));type=ifaceAndProtoJSClass->mType;returnifaceAndProtoJSClass->mNativeHooks;}// Try to resolve a property as an unforgeable property from the given// NativeProperties, if it's there. nativeProperties is allowed to be null (in// which case we of course won't resolve anything).staticboolXrayResolveUnforgeableProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc,constNativeProperties*nativeProperties);staticboolXrayResolveNativeProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,constNativePropertyHooks*nativePropertyHooks,DOMObjectTypetype,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc);boolXrayResolveOwnProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc,bool&cacheOnHolder){DOMObjectTypetype;boolisGlobal;constNativePropertyHooks*nativePropertyHooks=GetNativePropertyHooks(cx,obj,type,isGlobal);if(type!=eInstance||(isGlobal&&GlobalPropertiesAreOwn())){// For prototype objects and interface objects, just return their// normal set of properties. For global objects the WebIDL properties live// on the instance objects, so resolve those here too.if(!XrayResolveNativeProperty(cx,wrapper,nativePropertyHooks,type,obj,id,desc)){returnfalse;}// For non-global non-instance Xrays there are no other properties, so// return here for them whether we resolved the property or not.if(!isGlobal||desc.object()){cacheOnHolder=true;returntrue;}}// Check for unforgeable properties before doing mResolveOwnProperty weirdnessconstNativePropertiesHolder&nativeProperties=nativePropertyHooks->mNativeProperties;if(!XrayResolveUnforgeableProperty(cx,wrapper,obj,id,desc,nativeProperties.regular)){returnfalse;}if(desc.object()){cacheOnHolder=true;returntrue;}if(!XrayResolveUnforgeableProperty(cx,wrapper,obj,id,desc,nativeProperties.chromeOnly)){returnfalse;}if(desc.object()){cacheOnHolder=true;returntrue;}cacheOnHolder=false;return!nativePropertyHooks->mResolveOwnProperty||nativePropertyHooks->mResolveOwnProperty(cx,wrapper,obj,id,desc);}staticboolXrayResolveAttribute(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,constPrefable<constJSPropertySpec>*attributes,jsid*attributeIds,constJSPropertySpec*attributeSpecs,JS::MutableHandle<JSPropertyDescriptor>desc){for(;attributes->specs;++attributes){if(attributes->isEnabled(cx,obj)){// Set i to be the index into our full list of ids/specs that we're// looking at now.size_ti=attributes->specs-attributeSpecs;for(;attributeIds[i]!=JSID_VOID;++i){if(id==attributeIds[i]){constJSPropertySpec&attrSpec=attributeSpecs[i];// Because of centralization, we need to make sure we fault in the// JitInfos as well. At present, until the JSAPI changes, the easiest// way to do this is wrap them up as functions ourselves.desc.setAttributes(attrSpec.flags&~JSPROP_NATIVE_ACCESSORS);// They all have getters, so we can just make it.JS::Rooted<JSFunction*>fun(cx,JS_NewFunctionById(cx,(JSNative)attrSpec.getter.propertyOp.op,0,0,wrapper,id));if(!fun)returnfalse;SET_JITINFO(fun,attrSpec.getter.propertyOp.info);JSObject*funobj=JS_GetFunctionObject(fun);desc.setGetterObject(funobj);desc.attributesRef()|=JSPROP_GETTER;if(attrSpec.setter.propertyOp.op){// We have a setter! Make it.fun=JS_NewFunctionById(cx,(JSNative)attrSpec.setter.propertyOp.op,1,0,wrapper,id);if(!fun)returnfalse;SET_JITINFO(fun,attrSpec.setter.propertyOp.info);funobj=JS_GetFunctionObject(fun);desc.setSetterObject(funobj);desc.attributesRef()|=JSPROP_SETTER;}else{desc.setSetter(nullptr);}desc.object().set(wrapper);returntrue;}}}}returntrue;}/* static */boolXrayResolveUnforgeableProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc,constNativeProperties*nativeProperties){return!nativeProperties||!nativeProperties->unforgeableAttributes||XrayResolveAttribute(cx,wrapper,obj,id,nativeProperties->unforgeableAttributes,nativeProperties->unforgeableAttributeIds,nativeProperties->unforgeableAttributeSpecs,desc);}staticboolXrayResolveProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc,DOMObjectTypetype,constNativeProperties*nativeProperties){constPrefable<constJSFunctionSpec>*methods;jsid*methodIds;constJSFunctionSpec*methodsSpecs;if(type==eInterface){methods=nativeProperties->staticMethods;methodIds=nativeProperties->staticMethodIds;methodsSpecs=nativeProperties->staticMethodsSpecs;}else{methods=nativeProperties->methods;methodIds=nativeProperties->methodIds;methodsSpecs=nativeProperties->methodsSpecs;}if(methods){constPrefable<constJSFunctionSpec>*method;for(method=methods;method->specs;++method){if(method->isEnabled(cx,obj)){// Set i to be the index into our full list of ids/specs that we're// looking at now.size_ti=method->specs-methodsSpecs;for(;methodIds[i]!=JSID_VOID;++i){if(id==methodIds[i]){constJSFunctionSpec&methodSpec=methodsSpecs[i];JSFunction*fun;if(methodSpec.selfHostedName){fun=JS::GetSelfHostedFunction(cx,methodSpec.selfHostedName,id,methodSpec.nargs);if(!fun){returnfalse;}MOZ_ASSERT(!methodSpec.call.op,"Bad FunctionSpec declaration: non-null native");MOZ_ASSERT(!methodSpec.call.info,"Bad FunctionSpec declaration: non-null jitinfo");}else{fun=JS_NewFunctionById(cx,methodSpec.call.op,methodSpec.nargs,0,wrapper,id);if(!fun){returnfalse;}SET_JITINFO(fun,methodSpec.call.info);}JSObject*funobj=JS_GetFunctionObject(fun);desc.value().setObject(*funobj);desc.setAttributes(methodSpec.flags);desc.object().set(wrapper);desc.setSetter(nullptr);desc.setGetter(nullptr);returntrue;}}}}}if(type==eInterface){if(nativeProperties->staticAttributes){if(!XrayResolveAttribute(cx,wrapper,obj,id,nativeProperties->staticAttributes,nativeProperties->staticAttributeIds,nativeProperties->staticAttributeSpecs,desc)){returnfalse;}if(desc.object()){returntrue;}}}else{if(nativeProperties->attributes){if(!XrayResolveAttribute(cx,wrapper,obj,id,nativeProperties->attributes,nativeProperties->attributeIds,nativeProperties->attributeSpecs,desc)){returnfalse;}if(desc.object()){returntrue;}}}if(nativeProperties->constants){constPrefable<constConstantSpec>*constant;for(constant=nativeProperties->constants;constant->specs;++constant){if(constant->isEnabled(cx,obj)){// Set i to be the index into our full list of ids/specs that we're// looking at now.size_ti=constant->specs-nativeProperties->constantSpecs;for(;nativeProperties->constantIds[i]!=JSID_VOID;++i){if(id==nativeProperties->constantIds[i]){desc.setAttributes(JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);desc.object().set(wrapper);desc.value().set(nativeProperties->constantSpecs[i].value);returntrue;}}}}}returntrue;}staticboolResolvePrototypeOrConstructor(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,size_tprotoAndIfaceCacheIndex,unsignedattrs,JS::MutableHandle<JSPropertyDescriptor>desc){JS::Rooted<JSObject*>global(cx,js::GetGlobalForObjectCrossCompartment(obj));{JSAutoCompartmentac(cx,global);ProtoAndIfaceCache&protoAndIfaceCache=*GetProtoAndIfaceCache(global);JSObject*protoOrIface=protoAndIfaceCache.EntrySlotIfExists(protoAndIfaceCacheIndex);if(!protoOrIface){returnfalse;}desc.object().set(wrapper);desc.setAttributes(attrs);desc.setGetter(JS_PropertyStub);desc.setSetter(JS_StrictPropertyStub);desc.value().set(JS::ObjectValue(*protoOrIface));}returnJS_WrapPropertyDescriptor(cx,desc);}/* static */boolXrayResolveNativeProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,constNativePropertyHooks*nativePropertyHooks,DOMObjectTypetype,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc){if(type==eInterface&&IdEquals(id,"prototype")){returnnativePropertyHooks->mPrototypeID==prototypes::id::_ID_Count||ResolvePrototypeOrConstructor(cx,wrapper,obj,nativePropertyHooks->mPrototypeID,JSPROP_PERMANENT|JSPROP_READONLY,desc);}if(type==eInterfacePrototype&&IdEquals(id,"constructor")){returnnativePropertyHooks->mConstructorID==constructors::id::_ID_Count||ResolvePrototypeOrConstructor(cx,wrapper,obj,nativePropertyHooks->mConstructorID,0,desc);}constNativePropertiesHolder&nativeProperties=nativePropertyHooks->mNativeProperties;if(nativeProperties.regular&&!XrayResolveProperty(cx,wrapper,obj,id,desc,type,nativeProperties.regular)){returnfalse;}if(!desc.object()&&nativeProperties.chromeOnly&&xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper))&&!XrayResolveProperty(cx,wrapper,obj,id,desc,type,nativeProperties.chromeOnly)){returnfalse;}returntrue;}boolXrayResolveNativeProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc){DOMObjectTypetype;boolisGlobal;constNativePropertyHooks*nativePropertyHooks=GetNativePropertyHooks(cx,obj,type,isGlobal);if(type==eInstance){// Global objects return their interfaces' properties from// XrayResolveOwnProperty, so skip those.if((isGlobal&&GlobalPropertiesAreOwn())&&!(nativePropertyHooks=nativePropertyHooks->mProtoHooks)){returntrue;}// Force the type to be eInterfacePrototype, since we need to walk the// prototype chain.type=eInterfacePrototype;}if(type==eInterfacePrototype){do{if(!XrayResolveNativeProperty(cx,wrapper,nativePropertyHooks,type,obj,id,desc)){returnfalse;}if(desc.object()){returntrue;}}while((nativePropertyHooks=nativePropertyHooks->mProtoHooks));returntrue;}returnXrayResolveNativeProperty(cx,wrapper,nativePropertyHooks,type,obj,id,desc);}boolXrayDefineProperty(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,JS::Handle<jsid>id,JS::MutableHandle<JSPropertyDescriptor>desc,bool*defined){if(!js::IsProxy(obj))returntrue;MOZ_ASSERT(IsDOMProxy(obj),"What kind of proxy is this?");DOMProxyHandler*handler=static_cast<DOMProxyHandler*>(js::GetProxyHandler(obj));returnhandler->defineProperty(cx,wrapper,id,desc,defined);}boolXrayEnumerateAttributes(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,constPrefable<constJSPropertySpec>*attributes,jsid*attributeIds,constJSPropertySpec*attributeSpecs,unsignedflags,JS::AutoIdVector&props){for(;attributes->specs;++attributes){if(attributes->isEnabled(cx,obj)){// Set i to be the index into our full list of ids/specs that we're// looking at now.size_ti=attributes->specs-attributeSpecs;for(;attributeIds[i]!=JSID_VOID;++i){if(((flags&JSITER_HIDDEN)||(attributeSpecs[i].flags&JSPROP_ENUMERATE))&&!props.append(attributeIds[i])){returnfalse;}}}}returntrue;}boolXrayEnumerateProperties(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,unsignedflags,JS::AutoIdVector&props,DOMObjectTypetype,constNativeProperties*nativeProperties){constPrefable<constJSFunctionSpec>*methods;jsid*methodIds;constJSFunctionSpec*methodsSpecs;if(type==eInterface){methods=nativeProperties->staticMethods;methodIds=nativeProperties->staticMethodIds;methodsSpecs=nativeProperties->staticMethodsSpecs;}else{methods=nativeProperties->methods;methodIds=nativeProperties->methodIds;methodsSpecs=nativeProperties->methodsSpecs;}if(methods){constPrefable<constJSFunctionSpec>*method;for(method=methods;method->specs;++method){if(method->isEnabled(cx,obj)){// Set i to be the index into our full list of ids/specs that we're// looking at now.size_ti=method->specs-methodsSpecs;for(;methodIds[i]!=JSID_VOID;++i){if(((flags&JSITER_HIDDEN)||(methodsSpecs[i].flags&JSPROP_ENUMERATE))&&!props.append(methodIds[i])){returnfalse;}}}}}if(type==eInterface){if(nativeProperties->staticAttributes&&!XrayEnumerateAttributes(cx,wrapper,obj,nativeProperties->staticAttributes,nativeProperties->staticAttributeIds,nativeProperties->staticAttributeSpecs,flags,props)){returnfalse;}}else{if(nativeProperties->attributes&&!XrayEnumerateAttributes(cx,wrapper,obj,nativeProperties->attributes,nativeProperties->attributeIds,nativeProperties->attributeSpecs,flags,props)){returnfalse;}if(nativeProperties->unforgeableAttributes&&!XrayEnumerateAttributes(cx,wrapper,obj,nativeProperties->unforgeableAttributes,nativeProperties->unforgeableAttributeIds,nativeProperties->unforgeableAttributeSpecs,flags,props)){returnfalse;}}if(nativeProperties->constants){constPrefable<constConstantSpec>*constant;for(constant=nativeProperties->constants;constant->specs;++constant){if(constant->isEnabled(cx,obj)){// Set i to be the index into our full list of ids/specs that we're// looking at now.size_ti=constant->specs-nativeProperties->constantSpecs;for(;nativeProperties->constantIds[i]!=JSID_VOID;++i){if(!props.append(nativeProperties->constantIds[i])){returnfalse;}}}}}returntrue;}boolXrayEnumerateNativeProperties(JSContext*cx,JS::Handle<JSObject*>wrapper,constNativePropertyHooks*nativePropertyHooks,DOMObjectTypetype,JS::Handle<JSObject*>obj,unsignedflags,JS::AutoIdVector&props){if(type==eInterface&&nativePropertyHooks->mPrototypeID!=prototypes::id::_ID_Count&&!AddStringToIDVector(cx,props,"prototype")){returnfalse;}if(type==eInterfacePrototype&&nativePropertyHooks->mConstructorID!=constructors::id::_ID_Count&&(flags&JSITER_HIDDEN)&&!AddStringToIDVector(cx,props,"constructor")){returnfalse;}constNativePropertiesHolder&nativeProperties=nativePropertyHooks->mNativeProperties;if(nativeProperties.regular&&!XrayEnumerateProperties(cx,wrapper,obj,flags,props,type,nativeProperties.regular)){returnfalse;}if(nativeProperties.chromeOnly&&xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper))&&!XrayEnumerateProperties(cx,wrapper,obj,flags,props,type,nativeProperties.chromeOnly)){returnfalse;}returntrue;}boolXrayEnumerateProperties(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,unsignedflags,JS::AutoIdVector&props){DOMObjectTypetype;boolisGlobal;constNativePropertyHooks*nativePropertyHooks=GetNativePropertyHooks(cx,obj,type,isGlobal);if(type==eInstance){if(nativePropertyHooks->mEnumerateOwnProperties&&!nativePropertyHooks->mEnumerateOwnProperties(cx,wrapper,obj,props)){returnfalse;}if(!(isGlobal&&GlobalPropertiesAreOwn())&&(flags&JSITER_OWNONLY)){returntrue;}// Force the type to be eInterfacePrototype, since we need to walk the// prototype chain.type=eInterfacePrototype;}if(type==eInterfacePrototype){do{if(!XrayEnumerateNativeProperties(cx,wrapper,nativePropertyHooks,type,obj,flags,props)){returnfalse;}if(flags&JSITER_OWNONLY){returntrue;}}while((nativePropertyHooks=nativePropertyHooks->mProtoHooks));returntrue;}returnXrayEnumerateNativeProperties(cx,wrapper,nativePropertyHooks,type,obj,flags,props);}NativePropertyHookssWorkerNativePropertyHooks={nullptr,nullptr,{nullptr,nullptr},prototypes::id::_ID_Count,constructors::id::_ID_Count,nullptr};boolGetPropertyOnPrototype(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,bool*found,JS::Value*vp){JS::Rooted<JSObject*>proto(cx);if(!js::GetObjectProto(cx,proxy,&proto)){returnfalse;}if(!proto){*found=false;returntrue;}boolhasProp;if(!JS_HasPropertyById(cx,proto,id,&hasProp)){returnfalse;}*found=hasProp;if(!hasProp||!vp){returntrue;}JS::Rooted<JS::Value>value(cx);if(!JS_ForwardGetPropertyTo(cx,proto,id,proxy,&value)){returnfalse;}*vp=value;returntrue;}boolHasPropertyOnPrototype(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id){JS::Rooted<JSObject*>obj(cx,proxy);Maybe<JSAutoCompartment>ac;if(xpc::WrapperFactory::IsXrayWrapper(obj)){obj=js::UncheckedUnwrap(obj);ac.construct(cx,obj);}boolfound;// We ignore an error from GetPropertyOnPrototype. We pass nullptr// for vp so that GetPropertyOnPrototype won't actually do a get.return!GetPropertyOnPrototype(cx,obj,id,&found,nullptr)||found;}boolAppendNamedPropertyIds(JSContext*cx,JS::Handle<JSObject*>proxy,nsTArray<nsString>&names,boolshadowPrototypeProperties,JS::AutoIdVector&props){for(uint32_ti=0;i<names.Length();++i){JS::Rooted<JS::Value>v(cx);if(!xpc::NonVoidStringToJsval(cx,names[i],&v)){returnfalse;}JS::Rooted<jsid>id(cx);if(!JS_ValueToId(cx,v,&id)){returnfalse;}if(shadowPrototypeProperties||!HasPropertyOnPrototype(cx,proxy,id)){if(!props.append(id)){returnfalse;}}}returntrue;}boolDictionaryBase::ParseJSON(JSContext*aCx,constnsAString&aJSON,JS::MutableHandle<JS::Value>aVal){if(aJSON.IsEmpty()){returntrue;}returnJS_ParseJSON(aCx,static_cast<constjschar*>(PromiseFlatString(aJSON).get()),aJSON.Length(),aVal);}staticJSString*ConcatJSString(JSContext*cx,constchar*pre,JS::Handle<JSString*>str,constchar*post){if(!str){returnnullptr;}JS::Rooted<JSString*>preString(cx,JS_NewStringCopyN(cx,pre,strlen(pre)));JS::Rooted<JSString*>postString(cx,JS_NewStringCopyN(cx,post,strlen(post)));if(!preString||!postString){returnnullptr;}preString=JS_ConcatStrings(cx,preString,str);if(!preString){returnnullptr;}returnJS_ConcatStrings(cx,preString,postString);}boolNativeToString(JSContext*cx,JS::Handle<JSObject*>wrapper,JS::Handle<JSObject*>obj,constchar*pre,constchar*post,JS::MutableHandle<JS::Value>v){JS::Rooted<JSPropertyDescriptor>toStringDesc(cx);toStringDesc.object().set(nullptr);toStringDesc.setAttributes(0);toStringDesc.setGetter(nullptr);toStringDesc.setSetter(nullptr);toStringDesc.value().set(JS::UndefinedValue());JS::Rooted<jsid>id(cx,nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING));if(!XrayResolveNativeProperty(cx,wrapper,obj,id,&toStringDesc)){returnfalse;}JS::Rooted<JSString*>str(cx);{JSAutoCompartmentac(cx,obj);if(toStringDesc.object()){JS::Rooted<JS::Value>toString(cx,toStringDesc.value());if(!JS_WrapValue(cx,&toString)){returnfalse;}MOZ_ASSERT(JS_ObjectIsCallable(cx,&toString.toObject()));JS::Rooted<JS::Value>toStringResult(cx);if(JS_CallFunctionValue(cx,obj,toString,JS::HandleValueArray::empty(),&toStringResult)){str=toStringResult.toString();}else{str=nullptr;}}else{constjs::Class*clasp=js::GetObjectClass(obj);if(IsDOMClass(clasp)){str=JS_NewStringCopyZ(cx,clasp->name);str=ConcatJSString(cx,"[object ",str,"]");}elseif(IsDOMIfaceAndProtoClass(clasp)){constDOMIfaceAndProtoJSClass*ifaceAndProtoJSClass=DOMIfaceAndProtoJSClass::FromJSClass(clasp);str=JS_NewStringCopyZ(cx,ifaceAndProtoJSClass->mToString);}else{MOZ_ASSERT(JS_IsNativeFunction(obj,Constructor));JS::Rooted<JSFunction*>fun(cx,JS_GetObjectFunction(obj));str=JS_DecompileFunction(cx,fun,0);}str=ConcatJSString(cx,pre,str,post);}}if(!str){returnfalse;}v.setString(str);returnJS_WrapValue(cx,v);}// Dynamically ensure that two objects don't end up with the same reserved slot.classMOZ_STACK_CLASSAutoCloneDOMObjectSlotGuard{public:AutoCloneDOMObjectSlotGuard(JSContext*aCx,JSObject*aOld,JSObject*aNew):mOldReflector(aCx,aOld),mNewReflector(aCx,aNew){MOZ_ASSERT(js::GetReservedSlot(aOld,DOM_OBJECT_SLOT)==js::GetReservedSlot(aNew,DOM_OBJECT_SLOT));}~AutoCloneDOMObjectSlotGuard(){if(js::GetReservedSlot(mOldReflector,DOM_OBJECT_SLOT).toPrivate()){js::SetReservedSlot(mNewReflector,DOM_OBJECT_SLOT,JS::PrivateValue(nullptr));}}private:JS::Rooted<JSObject*>mOldReflector;JS::Rooted<JSObject*>mNewReflector;};nsresultReparentWrapper(JSContext*aCx,JS::Handle<JSObject*>aObjArg){js::AssertSameCompartment(aCx,aObjArg);// Check if we're near the stack limit before we get anywhere near the// transplanting code.JS_CHECK_RECURSION(aCx,returnNS_ERROR_FAILURE);JS::Rooted<JSObject*>aObj(aCx,aObjArg);constDOMClass*domClass=GetDOMClass(aObj);JS::Rooted<JSObject*>oldParent(aCx,JS_GetParent(aObj));JS::Rooted<JSObject*>newParent(aCx,domClass->mGetParent(aCx,aObj));JSAutoCompartmentoldAc(aCx,oldParent);JSCompartment*oldCompartment=js::GetObjectCompartment(oldParent);JSCompartment*newCompartment=js::GetObjectCompartment(newParent);if(oldCompartment==newCompartment){if(!JS_SetParent(aCx,aObj,newParent)){MOZ_CRASH();}returnNS_OK;}// Telemetry.xpc::RecordDonatedNode(oldCompartment);xpc::RecordAdoptedNode(newCompartment);nsISupports*native=UnwrapDOMObjectToISupports(aObj);if(!native){returnNS_OK;}boolisProxy=js::IsProxy(aObj);JS::Rooted<JSObject*>expandoObject(aCx);if(isProxy){expandoObject=DOMProxyHandler::GetAndClearExpandoObject(aObj);}JSAutoCompartmentnewAc(aCx,newParent);// First we clone the reflector. We get a copy of its properties and clone its// expando chain. The only part that is dangerous here is that if we have to// return early we must avoid ending up with two reflectors pointing to the// same native. Other than that, the objects we create will just go away.JS::Rooted<JSObject*>global(aCx,js::GetGlobalForObjectCrossCompartment(newParent));JS::Handle<JSObject*>proto=(domClass->mGetProto)(aCx,global);if(!proto){returnNS_ERROR_FAILURE;}JS::Rooted<JSObject*>newobj(aCx,JS_CloneObject(aCx,aObj,proto,newParent));if(!newobj){returnNS_ERROR_FAILURE;}js::SetReservedSlot(newobj,DOM_OBJECT_SLOT,js::GetReservedSlot(aObj,DOM_OBJECT_SLOT));// At this point, both |aObj| and |newobj| point to the same native// which is bad, because one of them will end up being finalized with a// native it does not own. |cloneGuard| ensures that if we exit before// clearing |aObj|'s reserved slot the reserved slot of |newobj| will be// set to null. |aObj| will go away soon, because we swap it with// another object during the transplant and let that object die.JS::Rooted<JSObject*>propertyHolder(aCx);{AutoCloneDOMObjectSlotGuardcloneGuard(aCx,aObj,newobj);JS::Rooted<JSObject*>copyFrom(aCx,isProxy?expandoObject:aObj);if(copyFrom){propertyHolder=JS_NewObjectWithGivenProto(aCx,nullptr,JS::NullPtr(),newParent);if(!propertyHolder){returnNS_ERROR_OUT_OF_MEMORY;}if(!JS_CopyPropertiesFrom(aCx,propertyHolder,copyFrom)){returnNS_ERROR_FAILURE;}}else{propertyHolder=nullptr;}// Expandos from other compartments are attached to the target JS object.// Copy them over, and let the old ones die a natural death.if(!xpc::XrayUtils::CloneExpandoChain(aCx,newobj,aObj)){returnNS_ERROR_FAILURE;}// We've set up |newobj|, so we make it own the native by nulling// out the reserved slot of |obj|.//// NB: It's important to do this _after_ copying the properties to// propertyHolder. Otherwise, an object with |foo.x === foo| will// crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.js::SetReservedSlot(aObj,DOM_OBJECT_SLOT,JS::PrivateValue(nullptr));}aObj=xpc::TransplantObject(aCx,aObj,newobj);if(!aObj){MOZ_CRASH();}nsWrapperCache*cache=nullptr;CallQueryInterface(native,&cache);boolpreserving=cache->PreservingWrapper();cache->SetPreservingWrapper(false);cache->SetWrapper(aObj);cache->SetPreservingWrapper(preserving);if(propertyHolder){JS::Rooted<JSObject*>copyTo(aCx);if(isProxy){copyTo=DOMProxyHandler::EnsureExpandoObject(aCx,aObj);}else{copyTo=aObj;}if(!copyTo||!JS_CopyPropertiesFrom(aCx,copyTo,propertyHolder)){MOZ_CRASH();}}nsObjectLoadingContent*htmlobject;nsresultrv=UNWRAP_OBJECT(HTMLObjectElement,aObj,htmlobject);if(NS_FAILED(rv)){rv=UnwrapObject<prototypes::id::HTMLEmbedElement,HTMLSharedObjectElement>(aObj,htmlobject);if(NS_FAILED(rv)){rv=UnwrapObject<prototypes::id::HTMLAppletElement,HTMLSharedObjectElement>(aObj,htmlobject);if(NS_FAILED(rv)){htmlobject=nullptr;}}}if(htmlobject){htmlobject->SetupProtoChain(aCx,aObj);}// Now we can just fix up the parent and return the wrapperif(newParent&&!JS_SetParent(aCx,aObj,newParent)){MOZ_CRASH();}returnNS_OK;}GlobalObject::GlobalObject(JSContext*aCx,JSObject*aObject):mGlobalJSObject(aCx),mCx(aCx),mGlobalObject(nullptr){JS::Rooted<JSObject*>obj(aCx,aObject);if(js::IsWrapper(obj)){obj=js::CheckedUnwrap(obj,/* stopAtOuter = */false);if(!obj){// We should never end up here on a worker thread, since there shouldn't// be any security wrappers to worry about.if(!MOZ_LIKELY(NS_IsMainThread())){MOZ_CRASH();}Throw(aCx,NS_ERROR_XPC_SECURITY_MANAGER_VETO);return;}}mGlobalJSObject=js::GetGlobalForObjectCrossCompartment(obj);}nsISupports*GlobalObject::GetAsSupports()const{if(mGlobalObject){returnmGlobalObject;}if(!NS_IsMainThread()){mGlobalObject=UnwrapDOMObjectToISupports(mGlobalJSObject);returnmGlobalObject;}JS::Rooted<JS::Value>val(mCx,JS::ObjectValue(*mGlobalJSObject));// Switch this to UnwrapDOMObjectToISupports once our global objects are// using new bindings.nsresultrv=xpc_qsUnwrapArg<nsISupports>(mCx,val,&mGlobalObject,static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)),&val);if(NS_FAILED(rv)){mGlobalObject=nullptr;Throw(mCx,NS_ERROR_XPC_BAD_CONVERT_JS);}returnmGlobalObject;}boolInterfaceHasInstance(JSContext*cx,JS::Handle<JSObject*>obj,JS::Handle<JSObject*>instance,bool*bp){constDOMIfaceAndProtoJSClass*clasp=DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));constDOMClass*domClass=GetDOMClass(js::UncheckedUnwrap(instance));MOZ_ASSERT(!domClass||clasp->mPrototypeID!=prototypes::id::_ID_Count,"Why do we have a hasInstance hook if we don't have a prototype ""ID?");if(domClass&&domClass->mInterfaceChain[clasp->mDepth]==clasp->mPrototypeID){*bp=true;returntrue;}JS::Rooted<JSObject*>unwrapped(cx,js::CheckedUnwrap(instance,true));if(unwrapped&&jsipc::JavaScriptParent::IsCPOW(unwrapped)){boolboolp=false;if(!jsipc::JavaScriptParent::DOMInstanceOf(cx,unwrapped,clasp->mPrototypeID,clasp->mDepth,&boolp)){returnfalse;}*bp=boolp;returntrue;}JS::Rooted<JS::Value>protov(cx);DebugOnly<bool>ok=JS_GetProperty(cx,obj,"prototype",&protov);MOZ_ASSERT(ok,"Someone messed with our prototype property?");JS::Rooted<JSObject*>interfacePrototype(cx,&protov.toObject());MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),"Someone messed with our prototype property?");JS::Rooted<JSObject*>proto(cx);if(!JS_GetPrototype(cx,instance,&proto)){returnfalse;}while(proto){if(proto==interfacePrototype){*bp=true;returntrue;}if(!JS_GetPrototype(cx,proto,&proto)){returnfalse;}}*bp=false;returntrue;}boolInterfaceHasInstance(JSContext*cx,JS::Handle<JSObject*>obj,JS::MutableHandle<JS::Value>vp,bool*bp){if(!vp.isObject()){*bp=false;returntrue;}JS::Rooted<JSObject*>instanceObject(cx,&vp.toObject());returnInterfaceHasInstance(cx,obj,instanceObject,bp);}boolInterfaceHasInstance(JSContext*cx,intprototypeID,intdepth,JS::Handle<JSObject*>instance,bool*bp){constDOMClass*domClass=GetDOMClass(js::UncheckedUnwrap(instance));MOZ_ASSERT(!domClass||prototypeID!=prototypes::id::_ID_Count,"Why do we have a hasInstance hook if we don't have a prototype ""ID?");*bp=(domClass&&domClass->mInterfaceChain[depth]==prototypeID);returntrue;}boolReportLenientThisUnwrappingFailure(JSContext*cx,JSObject*obj){JS::Rooted<JSObject*>rootedObj(cx,obj);GlobalObjectglobal(cx,rootedObj);if(global.Failed()){returnfalse;}nsCOMPtr<nsPIDOMWindow>window=do_QueryInterface(global.GetAsSupports());if(window&&window->GetDoc()){window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);}returntrue;}boolGetWindowForJSImplementedObject(JSContext*cx,JS::Handle<JSObject*>obj,nsPIDOMWindow**window){// Be very careful to not get tricked here.MOZ_ASSERT(NS_IsMainThread());if(!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))){NS_RUNTIMEABORT("Should have a chrome object here");}// Look up the content-side object.JS::Rooted<JS::Value>domImplVal(cx);if(!JS_GetProperty(cx,obj,"__DOM_IMPL__",&domImplVal)){returnfalse;}if(!domImplVal.isObject()){ThrowErrorMessage(cx,MSG_NOT_OBJECT,"Value");returnfalse;}// Go ahead and get the global from it. GlobalObject will handle// doing unwrapping as needed.GlobalObjectglobal(cx,&domImplVal.toObject());if(global.Failed()){returnfalse;}// It's OK if we have null here: that just means the content-side// object really wasn't associated with any window.nsCOMPtr<nsPIDOMWindow>win(do_QueryInterface(global.GetAsSupports()));win.forget(window);returntrue;}already_AddRefed<nsPIDOMWindow>ConstructJSImplementation(JSContext*aCx,constchar*aContractId,constGlobalObject&aGlobal,JS::MutableHandle<JSObject*>aObject,ErrorResult&aRv){// Get the window to use as a parent and for initialization.nsCOMPtr<nsPIDOMWindow>window=do_QueryInterface(aGlobal.GetAsSupports());if(!window){aRv.Throw(NS_ERROR_FAILURE);returnnullptr;}ConstructJSImplementation(aCx,aContractId,window,aObject,aRv);if(aRv.Failed()){returnnullptr;}returnwindow.forget();}voidConstructJSImplementation(JSContext*aCx,constchar*aContractId,nsPIDOMWindow*aWindow,JS::MutableHandle<JSObject*>aObject,ErrorResult&aRv){// Make sure to divorce ourselves from the calling JS while creating and// initializing the object, so exceptions from that will get reported// properly, since those are never exceptions that a spec wants to be thrown.{AutoNoJSAPInojsapi;// Get the XPCOM component containing the JS implementation.nsCOMPtr<nsISupports>implISupports=do_CreateInstance(aContractId);if(!implISupports){NS_WARNING("Failed to get JS implementation for contract");aRv.Throw(NS_ERROR_FAILURE);return;}// Initialize the object, if it implements nsIDOMGlobalPropertyInitializer.nsCOMPtr<nsIDOMGlobalPropertyInitializer>gpi=do_QueryInterface(implISupports);if(gpi){JS::Rooted<JS::Value>initReturn(aCx);nsresultrv=gpi->Init(aWindow,&initReturn);if(NS_FAILED(rv)){aRv.Throw(rv);return;}// With JS-implemented WebIDL, the return value of init() is not used to determine// if init() failed, so init() should only return undefined. Any kind of permission// or pref checking must happen by adding an attribute to the WebIDL interface.if(!initReturn.isUndefined()){MOZ_ASSERT(false,"The init() method for JS-implemented WebIDL should not return anything");MOZ_CRASH();}}// Extract the JS implementation from the XPCOM object.nsCOMPtr<nsIXPConnectWrappedJS>implWrapped=do_QueryInterface(implISupports);MOZ_ASSERT(implWrapped,"Failed to get wrapped JS from XPCOM component.");if(!implWrapped){aRv.Throw(NS_ERROR_FAILURE);return;}aObject.set(implWrapped->GetJSObject());if(!aObject){aRv.Throw(NS_ERROR_FAILURE);}}}boolNonVoidByteStringToJsval(JSContext*cx,constnsACString&str,JS::MutableHandle<JS::Value>rval){// ByteStrings are not UTF-8 encoded.JSString*jsStr=JS_NewStringCopyN(cx,str.Data(),str.Length());if(!jsStr)returnfalse;rval.setString(jsStr);returntrue;}boolConvertJSValueToByteString(JSContext*cx,JS::Handle<JS::Value>v,JS::MutableHandle<JS::Value>pval,boolnullable,nsACString&result){JS::Rooted<JSString*>s(cx);if(v.isString()){s=v.toString();}else{if(nullable&&v.isNullOrUndefined()){result.SetIsVoid(true);returntrue;}s=JS::ToString(cx,v);if(!s){returnfalse;}pval.set(JS::StringValue(s));// Root the new string.}size_tlength;constjschar*chars=JS_GetStringCharsZAndLength(cx,s,&length);if(!chars){returnfalse;}// Conversion from Javascript string to ByteString is only valid if all// characters < 256.for(size_ti=0;i<length;i++){if(chars[i]>255){// The largest unsigned 64 bit number (18,446,744,073,709,551,615) has// 20 digits, plus one more for the null terminator.charindex[21];static_assert(sizeof(size_t)<=8,"index array too small");PR_snprintf(index,sizeof(index),"%d",i);// A jschar is 16 bits long. The biggest unsigned 16 bit// number (65,535) has 5 digits, plus one more for the null// terminator.charbadChar[6];static_assert(sizeof(jschar)<=2,"badChar array too small");PR_snprintf(badChar,sizeof(badChar),"%d",chars[i]);ThrowErrorMessage(cx,MSG_INVALID_BYTESTRING,index,badChar);returnfalse;}}if(length>=UINT32_MAX){returnfalse;}result.SetCapacity(length+1);JS_EncodeStringToBuffer(cx,s,result.BeginWriting(),length);result.BeginWriting()[length]='\0';result.SetLength(length);returntrue;}boolIsInPrivilegedApp(JSContext*aCx,JSObject*aObj){usingmozilla::dom::workers::GetWorkerPrivateFromContext;if(!NS_IsMainThread()){returnGetWorkerPrivateFromContext(aCx)->IsInPrivilegedApp();}nsIPrincipal*principal=nsContentUtils::GetObjectPrincipal(aObj);uint16_tappStatus=principal->GetAppStatus();return(appStatus==nsIPrincipal::APP_STATUS_CERTIFIED||appStatus==nsIPrincipal::APP_STATUS_PRIVILEGED);}boolIsInCertifiedApp(JSContext*aCx,JSObject*aObj){usingmozilla::dom::workers::GetWorkerPrivateFromContext;if(!NS_IsMainThread()){returnGetWorkerPrivateFromContext(aCx)->IsInCertifiedApp();}nsIPrincipal*principal=nsContentUtils::GetObjectPrincipal(aObj);returnprincipal->GetAppStatus()==nsIPrincipal::APP_STATUS_CERTIFIED;}#ifdef DEBUGvoidVerifyTraceProtoAndIfaceCacheCalled(JSTracer*trc,void**thingp,JSGCTraceKindkind){// We don't do anything here, we only want to verify that TraceProtoAndIfaceCache// was called.}#endifvoidFinalizeGlobal(JSFreeOp*aFreeOp,JSObject*aObj){MOZ_ASSERT(js::GetObjectClass(aObj)->flags&JSCLASS_DOM_GLOBAL);mozilla::dom::DestroyProtoAndIfaceCache(aObj);}boolResolveGlobal(JSContext*aCx,JS::Handle<JSObject*>aObj,JS::Handle<jsid>aId,JS::MutableHandle<JSObject*>aObjp){boolresolved;if(!JS_ResolveStandardClass(aCx,aObj,aId,&resolved)){returnfalse;}aObjp.set(resolved?aObj.get():nullptr);returntrue;}boolEnumerateGlobal(JSContext*aCx,JS::Handle<JSObject*>aObj){returnJS_EnumerateStandardClasses(aCx,aObj);}boolGenericBindingGetter(JSContext*cx,unsignedargc,JS::Value*vp){JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());prototypes::IDprotoID=static_cast<prototypes::ID>(info->protoID);if(!args.thisv().isObject()){returnThrowInvalidThis(cx,args,MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE,protoID);}JS::Rooted<JSObject*>obj(cx,&args.thisv().toObject());void*self;{nsresultrv=UnwrapObject<void>(obj,self,protoID,info->depth);if(NS_FAILED(rv)){returnThrowInvalidThis(cx,args,GetInvalidThisErrorForGetter(rv==NS_ERROR_XPC_SECURITY_MANAGER_VETO),protoID);}}MOZ_ASSERT(info->type()==JSJitInfo::Getter);JSJitGetterOpgetter=info->getter;returngetter(cx,obj,self,JSJitGetterCallArgs(args));}boolGenericBindingSetter(JSContext*cx,unsignedargc,JS::Value*vp){JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());prototypes::IDprotoID=static_cast<prototypes::ID>(info->protoID);if(!args.thisv().isObject()){returnThrowInvalidThis(cx,args,MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE,protoID);}JS::Rooted<JSObject*>obj(cx,&args.thisv().toObject());void*self;{nsresultrv=UnwrapObject<void>(obj,self,protoID,info->depth);if(NS_FAILED(rv)){returnThrowInvalidThis(cx,args,GetInvalidThisErrorForSetter(rv==NS_ERROR_XPC_SECURITY_MANAGER_VETO),protoID);}}if(args.length()==0){returnThrowNoSetterArg(cx,protoID);}MOZ_ASSERT(info->type()==JSJitInfo::Setter);JSJitSetterOpsetter=info->setter;if(!setter(cx,obj,self,JSJitSetterCallArgs(args))){returnfalse;}args.rval().set(JSVAL_VOID);returntrue;}boolGenericBindingMethod(JSContext*cx,unsignedargc,JS::Value*vp){JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());prototypes::IDprotoID=static_cast<prototypes::ID>(info->protoID);if(!args.thisv().isObject()){returnThrowInvalidThis(cx,args,MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE,protoID);}JS::Rooted<JSObject*>obj(cx,&args.thisv().toObject());void*self;{nsresultrv=UnwrapObject<void>(obj,self,protoID,info->depth);if(NS_FAILED(rv)){returnThrowInvalidThis(cx,args,GetInvalidThisErrorForMethod(rv==NS_ERROR_XPC_SECURITY_MANAGER_VETO),protoID);}}MOZ_ASSERT(info->type()==JSJitInfo::Method);JSJitMethodOpmethod=info->method;returnmethod(cx,obj,self,JSJitMethodCallArgs(args));}boolGenericPromiseReturningBindingMethod(JSContext*cx,unsignedargc,JS::Value*vp){// Make sure to save the callee before someone maybe messes with rval().JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);JS::Rooted<JSObject*>callee(cx,&args.callee());// We could invoke GenericBindingMethod here, but that involves an// extra call. Manually inline it instead.constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());prototypes::IDprotoID=static_cast<prototypes::ID>(info->protoID);if(!args.thisv().isObject()){ThrowInvalidThis(cx,args,MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE,protoID);returnConvertExceptionToPromise(cx,xpc::XrayAwareCalleeGlobal(callee),args.rval());}JS::Rooted<JSObject*>obj(cx,&args.thisv().toObject());void*self;{nsresultrv=UnwrapObject<void>(obj,self,protoID,info->depth);if(NS_FAILED(rv)){ThrowInvalidThis(cx,args,GetInvalidThisErrorForMethod(rv==NS_ERROR_XPC_SECURITY_MANAGER_VETO),protoID);returnConvertExceptionToPromise(cx,xpc::XrayAwareCalleeGlobal(callee),args.rval());}}MOZ_ASSERT(info->type()==JSJitInfo::Method);JSJitMethodOpmethod=info->method;boolok=method(cx,obj,self,JSJitMethodCallArgs(args));if(ok){returntrue;}returnConvertExceptionToPromise(cx,xpc::XrayAwareCalleeGlobal(callee),args.rval());}boolStaticMethodPromiseWrapper(JSContext*cx,unsignedargc,JS::Value*vp){// Make sure to save the callee before someone maybe messes with rval().JS::CallArgsargs=JS::CallArgsFromVp(argc,vp);JS::Rooted<JSObject*>callee(cx,&args.callee());constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());MOZ_ASSERT(info);MOZ_ASSERT(info->type()==JSJitInfo::StaticMethod);boolok=info->staticMethod(cx,argc,vp);if(ok){returntrue;}returnConvertExceptionToPromise(cx,xpc::XrayAwareCalleeGlobal(callee),args.rval());}boolConvertExceptionToPromise(JSContext*cx,JSObject*promiseScope,JS::MutableHandle<JS::Value>rval){GlobalObjectglobal(cx,promiseScope);if(global.Failed()){returnfalse;}JS::Rooted<JS::Value>exn(cx);if(!JS_GetPendingException(cx,&exn)){returnfalse;}JS_ClearPendingException(cx);ErrorResultrv;nsRefPtr<Promise>promise=Promise::Reject(global,cx,exn,rv);if(rv.Failed()){// We just give up. Make sure to not leak memory on the// ErrorResult, but then just put the original exception back.ThrowMethodFailedWithDetails(cx,rv,"","");JS_SetPendingException(cx,exn);returnfalse;}returnWrapNewBindingObject(cx,promise,rval);}/* static */voidCreateGlobalOptions<nsGlobalWindow>::TraceGlobal(JSTracer*aTrc,JSObject*aObj){mozilla::dom::TraceProtoAndIfaceCache(aTrc,aObj);xpc::GetCompartmentPrivate(aObj)->scope->TraceSelf(aTrc);}/* static */boolCreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext*aCx,JS::Handle<JSObject*>aGlobal){returnXPCWrappedNativeScope::GetNewOrUsed(aCx,aGlobal);}}// namespace dom}// namespace mozilla