1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* vim: set ts=2 sw=2 et tw=79: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "BindingUtils.h"
12 #include "JavaScriptParent.h"
14 #include "mozilla/DebugOnly.h"
15 #include "mozilla/FloatingPoint.h"
16 #include "mozilla/Assertions.h"
17 #include "mozilla/Preferences.h"
19 #include "AccessCheck.h"
20 #include "jsfriendapi.h"
21 #include "js/OldDebugAPI.h"
22 #include "nsContentUtils.h"
23 #include "nsGlobalWindow.h"
24 #include "nsIDOMGlobalPropertyInitializer.h"
25 #include "nsIPermissionManager.h"
26 #include "nsIPrincipal.h"
27 #include "nsIXPConnect.h"
28 #include "nsUTF8Utils.h"
29 #include "WrapperFactory.h"
30 #include "xpcprivate.h"
31 #include "XPCQuickStubs.h"
32 #include "XrayWrapper.h"
33 #include "nsPrintfCString.h"
36 #include "mozilla/dom/ScriptSettings.h"
37 #include "mozilla/dom/DOMError.h"
38 #include "mozilla/dom/DOMErrorBinding.h"
39 #include "mozilla/dom/HTMLObjectElement.h"
40 #include "mozilla/dom/HTMLObjectElementBinding.h"
41 #include "mozilla/dom/HTMLSharedObjectElement.h"
42 #include "mozilla/dom/HTMLEmbedElementBinding.h"
43 #include "mozilla/dom/HTMLAppletElementBinding.h"
44 #include "mozilla/dom/Promise.h"
45 #include "WorkerPrivate.h"
46 #include "nsDOMClassInfo.h"
51 JSErrorFormatString ErrorFormatString
[] = {
52 #define MSG_DEF(_name, _argc, _str) \
53 { _str, _argc, JSEXN_TYPEERR },
54 #include "mozilla/dom/Errors.msg"
58 const JSErrorFormatString
*
59 GetErrorMessage(void* aUserRef
, const unsigned aErrorNumber
)
61 MOZ_ASSERT(aErrorNumber
< ArrayLength(ErrorFormatString
));
62 return &ErrorFormatString
[aErrorNumber
];
66 ThrowErrorMessage(JSContext
* aCx
, const ErrNum aErrorNumber
, ...)
69 va_start(ap
, aErrorNumber
);
70 JS_ReportErrorNumberVA(aCx
, GetErrorMessage
, nullptr,
71 static_cast<const unsigned>(aErrorNumber
), ap
);
77 ThrowInvalidThis(JSContext
* aCx
, const JS::CallArgs
& aArgs
,
78 const ErrNum aErrorNumber
,
79 const char* aInterfaceName
)
81 NS_ConvertASCIItoUTF16
ifaceName(aInterfaceName
);
82 // This should only be called for DOM methods/getters/setters, which
83 // are JSNative-backed functions, so we can assume that
84 // JS_ValueToFunction and JS_GetFunctionDisplayId will both return
85 // non-null and that JS_GetStringCharsZ returns non-null.
86 JS::Rooted
<JSFunction
*> func(aCx
, JS_ValueToFunction(aCx
, aArgs
.calleev()));
88 JS::Rooted
<JSString
*> funcName(aCx
, JS_GetFunctionDisplayId(func
));
90 nsAutoJSString funcNameStr
;
91 if (!funcNameStr
.init(aCx
, funcName
)) {
94 JS_ReportErrorNumberUC(aCx
, GetErrorMessage
, nullptr,
95 static_cast<const unsigned>(aErrorNumber
),
96 funcNameStr
.get(), ifaceName
.get());
101 ThrowInvalidThis(JSContext
* aCx
, const JS::CallArgs
& aArgs
,
102 const ErrNum aErrorNumber
,
103 prototypes::ID aProtoId
)
105 return ThrowInvalidThis(aCx
, aArgs
, aErrorNumber
,
106 NamesOfInterfacesWithProtos(aProtoId
));
110 ThrowNoSetterArg(JSContext
* aCx
, prototypes::ID aProtoId
)
112 nsPrintfCString
errorMessage("%s attribute setter",
113 NamesOfInterfacesWithProtos(aProtoId
));
114 return ThrowErrorMessage(aCx
, MSG_MISSING_ARGUMENTS
, errorMessage
.get());
119 struct ErrorResult::Message
{
120 nsTArray
<nsString
> mArgs
;
121 dom::ErrNum mErrorNumber
;
125 ErrorResult::ThrowTypeError(const dom::ErrNum errorNumber
, ...)
128 va_start(ap
, errorNumber
);
129 if (IsJSException()) {
130 // We have rooted our mJSException, and we don't have the info
131 // needed to unroot here, so just bail.
134 "Ignoring ThrowTypeError call because we have a JS exception");
140 mResult
= NS_ERROR_TYPE_ERR
;
141 Message
* message
= new Message();
142 message
->mErrorNumber
= errorNumber
;
143 uint16_t argCount
= dom::GetErrorMessage(nullptr, errorNumber
)->argCount
;
144 MOZ_ASSERT(argCount
<= 10);
145 argCount
= std::min
<uint16_t>(argCount
, 10);
147 message
->mArgs
.AppendElement(*va_arg(ap
, nsString
*));
154 ErrorResult::ReportTypeError(JSContext
* aCx
)
156 MOZ_ASSERT(mMessage
, "ReportTypeError() can be called only once");
158 Message
* message
= mMessage
;
159 const uint32_t argCount
= message
->mArgs
.Length();
160 const jschar
* args
[11];
161 for (uint32_t i
= 0; i
< argCount
; ++i
) {
162 args
[i
] = message
->mArgs
.ElementAt(i
).get();
164 args
[argCount
] = nullptr;
166 JS_ReportErrorNumberUCArray(aCx
, dom::GetErrorMessage
, nullptr,
167 static_cast<const unsigned>(message
->mErrorNumber
),
168 argCount
> 0 ? args
: nullptr);
174 ErrorResult::ClearMessage()
183 ErrorResult::ThrowJSException(JSContext
* cx
, JS::Handle
<JS::Value
> exn
)
185 MOZ_ASSERT(mMightHaveUnreportedJSException
,
186 "Why didn't you tell us you planned to throw a JS exception?");
192 // Make sure mJSException is initialized _before_ we try to root it. But
193 // don't set it to exn yet, because we don't want to do that until after we
195 mJSException
= JS::UndefinedValue();
196 if (!js::AddRawValueRoot(cx
, &mJSException
, "ErrorResult::mJSException")) {
197 // Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
198 // in fact rooted mJSException.
199 mResult
= NS_ERROR_OUT_OF_MEMORY
;
202 mResult
= NS_ERROR_DOM_JS_EXCEPTION
;
207 ErrorResult::ReportJSException(JSContext
* cx
)
209 MOZ_ASSERT(!mMightHaveUnreportedJSException
,
210 "Why didn't you tell us you planned to handle JS exceptions?");
212 JS::Rooted
<JS::Value
> exception(cx
, mJSException
);
213 if (JS_WrapValue(cx
, &exception
)) {
214 JS_SetPendingException(cx
, exception
);
216 mJSException
= exception
;
217 // If JS_WrapValue failed, not much we can do about it... No matter
218 // what, go ahead and unroot mJSException.
219 js::RemoveRawValueRoot(cx
, &mJSException
);
223 ErrorResult::ReportJSExceptionFromJSImplementation(JSContext
* aCx
)
225 MOZ_ASSERT(!mMightHaveUnreportedJSException
,
226 "Why didn't you tell us you planned to handle JS exceptions?");
228 dom::DOMError
* domError
;
229 nsresult rv
= UNWRAP_OBJECT(DOMError
, &mJSException
.toObject(), domError
);
231 // Unwrapping really shouldn't fail here, if mExceptionHandling is set to
232 // eRethrowContentExceptions then the CallSetup destructor only stores an
233 // exception if it unwraps to DOMError. If we reach this then either
234 // mExceptionHandling wasn't set to eRethrowContentExceptions and we
235 // shouldn't be calling ReportJSExceptionFromJSImplementation or something
236 // went really wrong.
237 NS_RUNTIMEABORT("We stored a non-DOMError exception!");
241 domError
->GetMessage(message
);
243 JS_ReportError(aCx
, "%hs", message
.get());
244 js::RemoveRawValueRoot(aCx
, &mJSException
);
246 // We no longer have a useful exception but we do want to signal that an error
248 mResult
= NS_ERROR_FAILURE
;
252 ErrorResult::StealJSException(JSContext
* cx
,
253 JS::MutableHandle
<JS::Value
> value
)
255 MOZ_ASSERT(!mMightHaveUnreportedJSException
,
256 "Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException");
257 MOZ_ASSERT(IsJSException(), "No exception to steal");
259 value
.set(mJSException
);
260 js::RemoveRawValueRoot(cx
, &mJSException
);
265 ErrorResult::ReportNotEnoughArgsError(JSContext
* cx
,
266 const char* ifaceName
,
267 const char* memberName
)
269 MOZ_ASSERT(ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS
);
271 nsPrintfCString
errorMessage("%s.%s", ifaceName
, memberName
);
272 ThrowErrorMessage(cx
, dom::MSG_MISSING_ARGUMENTS
, errorMessage
.get());
278 DefineConstants(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
279 const ConstantSpec
* cs
)
281 JS::Rooted
<JS::Value
> value(cx
);
282 for (; cs
->name
; ++cs
) {
285 JS_DefineProperty(cx
, obj
, cs
->name
, value
,
286 JSPROP_ENUMERATE
| JSPROP_READONLY
| JSPROP_PERMANENT
);
295 Define(JSContext
* cx
, JS::Handle
<JSObject
*> obj
, const JSFunctionSpec
* spec
) {
296 return JS_DefineFunctions(cx
, obj
, spec
);
299 Define(JSContext
* cx
, JS::Handle
<JSObject
*> obj
, const JSPropertySpec
* spec
) {
300 return JS_DefineProperties(cx
, obj
, spec
);
303 Define(JSContext
* cx
, JS::Handle
<JSObject
*> obj
, const ConstantSpec
* spec
) {
304 return DefineConstants(cx
, obj
, spec
);
309 DefinePrefable(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
310 const Prefable
<T
>* props
)
313 MOZ_ASSERT(props
->specs
);
316 if (props
->isEnabled(cx
, obj
)) {
317 if (!Define(cx
, obj
, props
->specs
)) {
321 } while ((++props
)->specs
);
326 DefineUnforgeableMethods(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
327 const Prefable
<const JSFunctionSpec
>* props
)
329 return DefinePrefable(cx
, obj
, props
);
333 DefineUnforgeableAttributes(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
334 const Prefable
<const JSPropertySpec
>* props
)
336 return DefinePrefable(cx
, obj
, props
);
340 // We should use JSFunction objects for interface objects, but we need a custom
341 // hasInstance hook because we have new interface objects on prototype chains of
342 // old (XPConnect-based) bindings. Because Function.prototype.toString throws if
343 // passed a non-Function object we also need to provide our own toString method
344 // for interface objects.
347 TOSTRING_CLASS_RESERVED_SLOT
= 0,
348 TOSTRING_NAME_RESERVED_SLOT
= 1
352 InterfaceObjectToString(JSContext
* cx
, unsigned argc
, JS::Value
*vp
)
354 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
355 JS::Rooted
<JSObject
*> callee(cx
, &args
.callee());
357 if (!args
.thisv().isObject()) {
358 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr,
359 JSMSG_CANT_CONVERT_TO
, "null", "object");
363 JS::Value v
= js::GetFunctionNativeReserved(callee
,
364 TOSTRING_CLASS_RESERVED_SLOT
);
365 const JSClass
* clasp
= static_cast<const JSClass
*>(v
.toPrivate());
367 v
= js::GetFunctionNativeReserved(callee
, TOSTRING_NAME_RESERVED_SLOT
);
368 JSString
* jsname
= v
.toString();
371 if (!name
.init(cx
, jsname
)) {
375 if (js::GetObjectJSClass(&args
.thisv().toObject()) != clasp
) {
376 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr,
377 JSMSG_INCOMPATIBLE_PROTO
,
378 NS_ConvertUTF16toUTF8(name
).get(), "toString",
384 str
.AppendLiteral("function ");
386 str
.AppendLiteral("() {");
388 str
.AppendLiteral(" [native code]");
392 return xpc::NonVoidStringToJsval(cx
, str
, args
.rval());
396 Constructor(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
398 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
400 js::GetFunctionNativeReserved(&args
.callee(),
401 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT
);
402 const JSNativeHolder
* nativeHolder
=
403 static_cast<const JSNativeHolder
*>(v
.toPrivate());
404 return (nativeHolder
->mNative
)(cx
, argc
, vp
);
408 CreateConstructor(JSContext
* cx
, JS::Handle
<JSObject
*> global
, const char* name
,
409 const JSNativeHolder
* nativeHolder
, unsigned ctorNargs
)
411 JSFunction
* fun
= js::NewFunctionWithReserved(cx
, Constructor
, ctorNargs
,
412 JSFUN_CONSTRUCTOR
, global
,
418 JSObject
* constructor
= JS_GetFunctionObject(fun
);
419 js::SetFunctionNativeReserved(constructor
,
420 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT
,
421 js::PrivateValue(const_cast<JSNativeHolder
*>(nativeHolder
)));
426 DefineConstructor(JSContext
* cx
, JS::Handle
<JSObject
*> global
, const char* name
,
427 JS::Handle
<JSObject
*> constructor
)
430 if (!JS_AlreadyHasOwnProperty(cx
, global
, name
, &alreadyDefined
)) {
434 // This is Enumerable: False per spec.
435 return alreadyDefined
||
436 JS_DefineProperty(cx
, global
, name
, constructor
, 0);
440 CreateInterfaceObject(JSContext
* cx
, JS::Handle
<JSObject
*> global
,
441 JS::Handle
<JSObject
*> constructorProto
,
442 const JSClass
* constructorClass
,
443 const JSNativeHolder
* constructorNative
,
444 unsigned ctorNargs
, const NamedConstructor
* namedConstructors
,
445 JS::Handle
<JSObject
*> proto
,
446 const NativeProperties
* properties
,
447 const NativeProperties
* chromeOnlyProperties
,
448 const char* name
, bool defineOnGlobal
)
450 JS::Rooted
<JSObject
*> constructor(cx
);
451 if (constructorClass
) {
452 MOZ_ASSERT(constructorProto
);
453 constructor
= JS_NewObject(cx
, constructorClass
, constructorProto
, global
);
455 MOZ_ASSERT(constructorNative
);
456 MOZ_ASSERT(constructorProto
== JS_GetFunctionPrototype(cx
, global
));
457 constructor
= CreateConstructor(cx
, global
, name
, constructorNative
,
464 if (constructorClass
) {
465 // Have to shadow Function.prototype.toString, since that throws
466 // on things that are not js::FunctionClass.
467 JS::Rooted
<JSFunction
*> toString(cx
,
468 js::DefineFunctionWithReserved(cx
, constructor
,
470 InterfaceObjectToString
,
476 JSString
*str
= ::JS_InternString(cx
, name
);
480 JSObject
* toStringObj
= JS_GetFunctionObject(toString
);
481 js::SetFunctionNativeReserved(toStringObj
, TOSTRING_CLASS_RESERVED_SLOT
,
482 PRIVATE_TO_JSVAL(const_cast<JSClass
*>(constructorClass
)));
484 js::SetFunctionNativeReserved(toStringObj
, TOSTRING_NAME_RESERVED_SLOT
,
485 STRING_TO_JSVAL(str
));
487 if (!JS_DefineProperty(cx
, constructor
, "length", ctorNargs
,
488 JSPROP_READONLY
| JSPROP_PERMANENT
)) {
494 if (properties
->staticMethods
&&
495 !DefinePrefable(cx
, constructor
, properties
->staticMethods
)) {
499 if (properties
->staticAttributes
&&
500 !DefinePrefable(cx
, constructor
, properties
->staticAttributes
)) {
504 if (properties
->constants
&&
505 !DefinePrefable(cx
, constructor
, properties
->constants
)) {
510 if (chromeOnlyProperties
) {
511 if (chromeOnlyProperties
->staticMethods
&&
512 !DefinePrefable(cx
, constructor
, chromeOnlyProperties
->staticMethods
)) {
516 if (chromeOnlyProperties
->staticAttributes
&&
517 !DefinePrefable(cx
, constructor
,
518 chromeOnlyProperties
->staticAttributes
)) {
522 if (chromeOnlyProperties
->constants
&&
523 !DefinePrefable(cx
, constructor
, chromeOnlyProperties
->constants
)) {
528 if (proto
&& !JS_LinkConstructorAndPrototype(cx
, constructor
, proto
)) {
532 if (defineOnGlobal
&& !DefineConstructor(cx
, global
, name
, constructor
)) {
536 if (namedConstructors
) {
537 int namedConstructorSlot
= DOM_INTERFACE_SLOTS_BASE
;
538 while (namedConstructors
->mName
) {
539 JS::Rooted
<JSObject
*> namedConstructor(cx
,
540 CreateConstructor(cx
, global
, namedConstructors
->mName
,
541 &namedConstructors
->mHolder
,
542 namedConstructors
->mNargs
));
543 if (!namedConstructor
||
544 !JS_DefineProperty(cx
, namedConstructor
, "prototype",
545 proto
, JSPROP_PERMANENT
| JSPROP_READONLY
,
546 JS_PropertyStub
, JS_StrictPropertyStub
) ||
548 !DefineConstructor(cx
, global
, namedConstructors
->mName
,
549 namedConstructor
))) {
552 js::SetReservedSlot(constructor
, namedConstructorSlot
++,
553 JS::ObjectValue(*namedConstructor
));
562 DefineWebIDLBindingUnforgeablePropertiesOnXPCObject(JSContext
* cx
,
563 JS::Handle
<JSObject
*> obj
,
564 const NativeProperties
* properties
)
566 if (properties
->unforgeableAttributes
&&
567 !DefinePrefable(cx
, obj
, properties
->unforgeableAttributes
)) {
575 DefineWebIDLBindingPropertiesOnXPCObject(JSContext
* cx
,
576 JS::Handle
<JSObject
*> obj
,
577 const NativeProperties
* properties
)
579 if (properties
->methods
&&
580 !DefinePrefable(cx
, obj
, properties
->methods
)) {
584 if (properties
->attributes
&&
585 !DefinePrefable(cx
, obj
, properties
->attributes
)) {
593 CreateInterfacePrototypeObject(JSContext
* cx
, JS::Handle
<JSObject
*> global
,
594 JS::Handle
<JSObject
*> parentProto
,
595 const JSClass
* protoClass
,
596 const NativeProperties
* properties
,
597 const NativeProperties
* chromeOnlyProperties
)
599 JS::Rooted
<JSObject
*> ourProto(cx
,
600 JS_NewObjectWithUniqueType(cx
, protoClass
, parentProto
, global
));
602 !DefineProperties(cx
, ourProto
, properties
, chromeOnlyProperties
)) {
610 DefineProperties(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
611 const NativeProperties
* properties
,
612 const NativeProperties
* chromeOnlyProperties
)
615 if (properties
->methods
&&
616 !DefinePrefable(cx
, obj
, properties
->methods
)) {
620 if (properties
->attributes
&&
621 !DefinePrefable(cx
, obj
, properties
->attributes
)) {
625 if (properties
->constants
&&
626 !DefinePrefable(cx
, obj
, properties
->constants
)) {
631 if (chromeOnlyProperties
) {
632 if (chromeOnlyProperties
->methods
&&
633 !DefinePrefable(cx
, obj
, chromeOnlyProperties
->methods
)) {
637 if (chromeOnlyProperties
->attributes
&&
638 !DefinePrefable(cx
, obj
, chromeOnlyProperties
->attributes
)) {
642 if (chromeOnlyProperties
->constants
&&
643 !DefinePrefable(cx
, obj
, chromeOnlyProperties
->constants
)) {
652 CreateInterfaceObjects(JSContext
* cx
, JS::Handle
<JSObject
*> global
,
653 JS::Handle
<JSObject
*> protoProto
,
654 const JSClass
* protoClass
, JS::Heap
<JSObject
*>* protoCache
,
655 JS::Handle
<JSObject
*> constructorProto
,
656 const JSClass
* constructorClass
, const JSNativeHolder
* constructor
,
657 unsigned ctorNargs
, const NamedConstructor
* namedConstructors
,
658 JS::Heap
<JSObject
*>* constructorCache
,
659 const NativeProperties
* properties
,
660 const NativeProperties
* chromeOnlyProperties
,
661 const char* name
, bool defineOnGlobal
)
663 MOZ_ASSERT(protoClass
|| constructorClass
|| constructor
,
664 "Need at least one class or a constructor!");
665 MOZ_ASSERT(!((properties
&&
666 (properties
->methods
|| properties
->attributes
)) ||
667 (chromeOnlyProperties
&&
668 (chromeOnlyProperties
->methods
||
669 chromeOnlyProperties
->attributes
))) || protoClass
,
670 "Methods or properties but no protoClass!");
671 MOZ_ASSERT(!((properties
&&
672 (properties
->staticMethods
|| properties
->staticAttributes
)) ||
673 (chromeOnlyProperties
&&
674 (chromeOnlyProperties
->staticMethods
||
675 chromeOnlyProperties
->staticAttributes
))) ||
676 constructorClass
|| constructor
,
677 "Static methods but no constructorClass or constructor!");
678 MOZ_ASSERT(bool(name
) == bool(constructorClass
|| constructor
),
679 "Must have name precisely when we have an interface object");
680 MOZ_ASSERT(!constructorClass
|| !constructor
);
681 MOZ_ASSERT(!protoClass
== !protoCache
,
682 "If, and only if, there is an interface prototype object we need "
684 MOZ_ASSERT(!(constructorClass
|| constructor
) == !constructorCache
,
685 "If, and only if, there is an interface object we need to cache "
688 JS::Rooted
<JSObject
*> proto(cx
);
691 CreateInterfacePrototypeObject(cx
, global
, protoProto
, protoClass
,
692 properties
, chromeOnlyProperties
);
704 if (constructorClass
|| constructor
) {
705 interface
= CreateInterfaceObject(cx
, global
, constructorProto
,
706 constructorClass
, constructor
,
707 ctorNargs
, namedConstructors
, proto
,
708 properties
, chromeOnlyProperties
, name
,
712 // If we fail we need to make sure to clear the value of protoCache we
714 *protoCache
= nullptr;
718 *constructorCache
= interface
;
723 NativeInterface2JSObjectAndThrowIfFailed(JSContext
* aCx
,
724 JS::Handle
<JSObject
*> aScope
,
725 JS::MutableHandle
<JS::Value
> aRetval
,
726 xpcObjectHelper
& aHelper
,
728 bool aAllowNativeWrapper
)
730 js::AssertSameCompartment(aCx
, aScope
);
732 // Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
734 nsWrapperCache
*cache
= aHelper
.GetWrapperCache();
736 if (cache
&& cache
->IsDOMBinding()) {
737 JS::Rooted
<JSObject
*> obj(aCx
, cache
->GetWrapper());
739 obj
= cache
->WrapObject(aCx
);
742 if (obj
&& aAllowNativeWrapper
&& !JS_WrapObject(aCx
, &obj
)) {
747 aRetval
.setObject(*obj
);
752 MOZ_ASSERT(NS_IsMainThread());
754 if (!XPCConvert::NativeInterface2JSObject(aRetval
, nullptr, aHelper
, aIID
,
755 nullptr, aAllowNativeWrapper
, &rv
)) {
756 // I can't tell if NativeInterface2JSObject throws JS exceptions
757 // or not. This is a sloppy stab at the right semantics; the
758 // method really ought to be fixed to behave consistently.
759 if (!JS_IsExceptionPending(aCx
)) {
760 Throw(aCx
, NS_FAILED(rv
) ? rv
: NS_ERROR_UNEXPECTED
);
768 TryPreserveWrapper(JSObject
* obj
)
770 MOZ_ASSERT(IsDOMObject(obj
));
772 if (nsISupports
* native
= UnwrapDOMObjectToISupports(obj
)) {
773 nsWrapperCache
* cache
= nullptr;
774 CallQueryInterface(native
, &cache
);
776 cache
->PreserveWrapper(native
);
781 // If this DOMClass is not cycle collected, then it isn't wrappercached,
782 // so it does not need to be preserved. If it is cycle collected, then
783 // we can't tell if it is wrappercached or not, so we just return false.
784 const DOMJSClass
* domClass
= GetDOMClass(obj
);
785 return domClass
&& !domClass
->mParticipant
;
788 // Can only be called with a DOM JSClass.
790 InstanceClassHasProtoAtDepth(const js::Class
* clasp
,
791 uint32_t protoID
, uint32_t depth
)
793 const DOMJSClass
* domClass
= DOMJSClass::FromJSClass(clasp
);
794 return static_cast<uint32_t>(domClass
->mInterfaceChain
[depth
]) == protoID
;
797 // Only set allowNativeWrapper to false if you really know you need it, if in
798 // doubt use true. Setting it to false disables security wrappers.
800 XPCOMObjectToJsval(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
801 xpcObjectHelper
& helper
, const nsIID
* iid
,
802 bool allowNativeWrapper
, JS::MutableHandle
<JS::Value
> rval
)
804 if (!NativeInterface2JSObjectAndThrowIfFailed(cx
, scope
, rval
, helper
, iid
,
805 allowNativeWrapper
)) {
810 JSObject
* jsobj
= rval
.toObjectOrNull();
811 if (jsobj
&& !js::GetObjectParent(jsobj
))
812 NS_ASSERTION(js::GetObjectClass(jsobj
)->flags
& JSCLASS_IS_GLOBAL
,
813 "Why did we recreate this wrapper?");
820 VariantToJsval(JSContext
* aCx
, nsIVariant
* aVariant
,
821 JS::MutableHandle
<JS::Value
> aRetval
)
824 if (!XPCVariant::VariantDataToJS(aVariant
, &rv
, aRetval
)) {
825 // Does it throw? Who knows
826 if (!JS_IsExceptionPending(aCx
)) {
827 Throw(aCx
, NS_FAILED(rv
) ? rv
: NS_ERROR_UNEXPECTED
);
836 QueryInterface(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
838 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
839 JS::Rooted
<JS::Value
> thisv(cx
, JS_THIS(cx
, vp
));
843 // Get the object. It might be a security wrapper, in which case we do a checked
845 JS::Rooted
<JSObject
*> origObj(cx
, &thisv
.toObject());
846 JSObject
* obj
= js::CheckedUnwrap(origObj
, /* stopAtOuter = */ false);
848 JS_ReportError(cx
, "Permission denied to access object");
852 // Switch this to UnwrapDOMObjectToISupports once our global objects are
853 // using new bindings.
854 JS::Rooted
<JS::Value
> val(cx
, JS::ObjectValue(*obj
));
855 nsISupports
* native
= nullptr;
856 nsCOMPtr
<nsISupports
> nativeRef
;
857 xpc_qsUnwrapArg
<nsISupports
>(cx
, val
, &native
,
858 static_cast<nsISupports
**>(getter_AddRefs(nativeRef
)),
861 return Throw(cx
, NS_ERROR_FAILURE
);
865 return Throw(cx
, NS_ERROR_XPC_NOT_ENOUGH_ARGS
);
868 if (!args
[0].isObject()) {
869 return Throw(cx
, NS_ERROR_XPC_BAD_CONVERT_JS
);
874 if (NS_FAILED(xpc_qsUnwrapArg
<nsIJSID
>(cx
, args
[0], &iid
, &iidRef
.ptr
,
876 return Throw(cx
, NS_ERROR_XPC_BAD_CONVERT_JS
);
880 if (iid
->GetID()->Equals(NS_GET_IID(nsIClassInfo
))) {
882 nsCOMPtr
<nsIClassInfo
> ci
= do_QueryInterface(native
, &rv
);
884 return Throw(cx
, rv
);
887 return WrapObject(cx
, ci
, &NS_GET_IID(nsIClassInfo
), args
.rval());
890 nsCOMPtr
<nsISupports
> unused
;
891 nsresult rv
= native
->QueryInterface(*iid
->GetID(), getter_AddRefs(unused
));
893 return Throw(cx
, rv
);
901 GetInterfaceImpl(JSContext
* aCx
, nsIInterfaceRequestor
* aRequestor
,
902 nsWrapperCache
* aCache
, nsIJSID
* aIID
,
903 JS::MutableHandle
<JS::Value
> aRetval
, ErrorResult
& aError
)
905 const nsID
* iid
= aIID
->GetID();
907 nsRefPtr
<nsISupports
> result
;
908 aError
= aRequestor
->GetInterface(*iid
, getter_AddRefs(result
));
909 if (aError
.Failed()) {
913 if (!WrapObject(aCx
, result
, iid
, aRetval
)) {
914 aError
.Throw(NS_ERROR_FAILURE
);
919 UnforgeableValueOf(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
921 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
922 args
.rval().set(args
.thisv());
927 ThrowingConstructor(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
929 return ThrowErrorMessage(cx
, MSG_ILLEGAL_CONSTRUCTOR
);
933 ThrowConstructorWithoutNew(JSContext
* cx
, const char* name
)
935 return ThrowErrorMessage(cx
, MSG_CONSTRUCTOR_WITHOUT_NEW
, name
);
938 inline const NativePropertyHooks
*
939 GetNativePropertyHooks(JSContext
*cx
, JS::Handle
<JSObject
*> obj
,
942 const DOMJSClass
* domClass
= GetDOMClass(obj
);
945 return domClass
->mNativeHooks
;
948 if (JS_ObjectIsFunction(cx
, obj
)) {
949 MOZ_ASSERT(JS_IsNativeFunction(obj
, Constructor
));
952 js::GetFunctionNativeReserved(obj
,
953 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT
);
954 const JSNativeHolder
* nativeHolder
=
955 static_cast<const JSNativeHolder
*>(v
.toPrivate());
956 return nativeHolder
->mPropertyHooks
;
959 MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj
)));
960 const DOMIfaceAndProtoJSClass
* ifaceAndProtoJSClass
=
961 DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj
));
962 type
= ifaceAndProtoJSClass
->mType
;
963 return ifaceAndProtoJSClass
->mNativeHooks
;
966 // Try to resolve a property as an unforgeable property from the given
967 // NativeProperties, if it's there. nativeProperties is allowed to be null (in
968 // which case we of course won't resolve anything).
970 XrayResolveUnforgeableProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
971 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
972 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
974 const NativeProperties
* nativeProperties
);
977 XrayResolveNativeProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
978 const NativePropertyHooks
* nativePropertyHooks
,
979 DOMObjectType type
, JS::Handle
<JSObject
*> obj
,
981 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
982 bool& cacheOnHolder
);
985 XrayResolveOwnProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
986 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
987 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
990 cacheOnHolder
= false;
993 const NativePropertyHooks
*nativePropertyHooks
=
994 GetNativePropertyHooks(cx
, obj
, type
);
996 if (type
!= eInstance
) {
997 // For prototype objects and interface objects, just return their
998 // normal set of properties.
999 return XrayResolveNativeProperty(cx
, wrapper
, nativePropertyHooks
, type
,
1000 obj
, id
, desc
, cacheOnHolder
);
1003 // Check for unforgeable properties before doing mResolveOwnProperty weirdness
1004 const NativePropertiesHolder
& nativeProperties
=
1005 nativePropertyHooks
->mNativeProperties
;
1006 if (!XrayResolveUnforgeableProperty(cx
, wrapper
, obj
, id
, desc
, cacheOnHolder
,
1007 nativeProperties
.regular
)) {
1010 if (desc
.object()) {
1013 if (!XrayResolveUnforgeableProperty(cx
, wrapper
, obj
, id
, desc
, cacheOnHolder
,
1014 nativeProperties
.chromeOnly
)) {
1017 if (desc
.object()) {
1021 return !nativePropertyHooks
->mResolveOwnProperty
||
1022 nativePropertyHooks
->mResolveOwnProperty(cx
, wrapper
, obj
, id
, desc
);
1026 XrayResolveAttribute(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1027 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
1028 const Prefable
<const JSPropertySpec
>* attributes
, jsid
* attributeIds
,
1029 const JSPropertySpec
* attributeSpecs
, JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1030 bool& cacheOnHolder
)
1032 for (; attributes
->specs
; ++attributes
) {
1033 if (attributes
->isEnabled(cx
, obj
)) {
1034 // Set i to be the index into our full list of ids/specs that we're
1036 size_t i
= attributes
->specs
- attributeSpecs
;
1037 for ( ; attributeIds
[i
] != JSID_VOID
; ++i
) {
1038 if (id
== attributeIds
[i
]) {
1039 cacheOnHolder
= true;
1041 const JSPropertySpec
& attrSpec
= attributeSpecs
[i
];
1042 // Because of centralization, we need to make sure we fault in the
1043 // JitInfos as well. At present, until the JSAPI changes, the easiest
1044 // way to do this is wrap them up as functions ourselves.
1045 desc
.setAttributes(attrSpec
.flags
& ~JSPROP_NATIVE_ACCESSORS
);
1046 // They all have getters, so we can just make it.
1047 JS::Rooted
<JSFunction
*> fun(cx
,
1048 JS_NewFunctionById(cx
, (JSNative
)attrSpec
.getter
.propertyOp
.op
,
1049 0, 0, wrapper
, id
));
1052 SET_JITINFO(fun
, attrSpec
.getter
.propertyOp
.info
);
1053 JSObject
*funobj
= JS_GetFunctionObject(fun
);
1054 desc
.setGetterObject(funobj
);
1055 desc
.attributesRef() |= JSPROP_GETTER
;
1056 if (attrSpec
.setter
.propertyOp
.op
) {
1057 // We have a setter! Make it.
1058 fun
= JS_NewFunctionById(cx
, (JSNative
)attrSpec
.setter
.propertyOp
.op
, 1, 0,
1062 SET_JITINFO(fun
, attrSpec
.setter
.propertyOp
.info
);
1063 funobj
= JS_GetFunctionObject(fun
);
1064 desc
.setSetterObject(funobj
);
1065 desc
.attributesRef() |= JSPROP_SETTER
;
1067 desc
.setSetter(nullptr);
1069 desc
.object().set(wrapper
);
1079 XrayResolveMethod(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1080 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
1081 const Prefable
<const JSFunctionSpec
>* methods
,
1083 const JSFunctionSpec
* methodSpecs
,
1084 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1085 bool& cacheOnHolder
)
1087 const Prefable
<const JSFunctionSpec
>* method
;
1088 for (method
= methods
; method
->specs
; ++method
) {
1089 if (method
->isEnabled(cx
, obj
)) {
1090 // Set i to be the index into our full list of ids/specs that we're
1092 size_t i
= method
->specs
- methodSpecs
;
1093 for ( ; methodIds
[i
] != JSID_VOID
; ++i
) {
1094 if (id
== methodIds
[i
]) {
1095 cacheOnHolder
= true;
1097 const JSFunctionSpec
& methodSpec
= methodSpecs
[i
];
1099 if (methodSpec
.selfHostedName
) {
1100 fun
= JS::GetSelfHostedFunction(cx
, methodSpec
.selfHostedName
, id
, methodSpec
.nargs
);
1104 MOZ_ASSERT(!methodSpec
.call
.op
, "Bad FunctionSpec declaration: non-null native");
1105 MOZ_ASSERT(!methodSpec
.call
.info
, "Bad FunctionSpec declaration: non-null jitinfo");
1107 fun
= JS_NewFunctionById(cx
, methodSpec
.call
.op
, methodSpec
.nargs
, 0, wrapper
, id
);
1111 SET_JITINFO(fun
, methodSpec
.call
.info
);
1113 JSObject
*funobj
= JS_GetFunctionObject(fun
);
1114 desc
.value().setObject(*funobj
);
1115 desc
.setAttributes(methodSpec
.flags
);
1116 desc
.object().set(wrapper
);
1117 desc
.setSetter(nullptr);
1118 desc
.setGetter(nullptr);
1128 XrayResolveUnforgeableProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1129 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
1130 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1131 bool& cacheOnHolder
,
1132 const NativeProperties
* nativeProperties
)
1134 if (!nativeProperties
) {
1138 if (nativeProperties
->unforgeableAttributes
) {
1139 if (!XrayResolveAttribute(cx
, wrapper
, obj
, id
,
1140 nativeProperties
->unforgeableAttributes
,
1141 nativeProperties
->unforgeableAttributeIds
,
1142 nativeProperties
->unforgeableAttributeSpecs
,
1143 desc
, cacheOnHolder
)) {
1147 if (desc
.object()) {
1152 if (nativeProperties
->unforgeableMethods
) {
1153 if (!XrayResolveMethod(cx
, wrapper
, obj
, id
,
1154 nativeProperties
->unforgeableMethods
,
1155 nativeProperties
->unforgeableMethodIds
,
1156 nativeProperties
->unforgeableMethodSpecs
,
1157 desc
, cacheOnHolder
)) {
1161 if (desc
.object()) {
1170 XrayResolveProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1171 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
1172 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1173 bool& cacheOnHolder
, DOMObjectType type
,
1174 const NativeProperties
* nativeProperties
)
1176 const Prefable
<const JSFunctionSpec
>* methods
;
1178 const JSFunctionSpec
* methodSpecs
;
1179 if (type
== eInterface
) {
1180 methods
= nativeProperties
->staticMethods
;
1181 methodIds
= nativeProperties
->staticMethodIds
;
1182 methodSpecs
= nativeProperties
->staticMethodSpecs
;
1184 methods
= nativeProperties
->methods
;
1185 methodIds
= nativeProperties
->methodIds
;
1186 methodSpecs
= nativeProperties
->methodSpecs
;
1189 if (!XrayResolveMethod(cx
, wrapper
, obj
, id
, methods
, methodIds
,
1190 methodSpecs
, desc
, cacheOnHolder
)) {
1193 if (desc
.object()) {
1198 if (type
== eInterface
) {
1199 if (nativeProperties
->staticAttributes
) {
1200 if (!XrayResolveAttribute(cx
, wrapper
, obj
, id
,
1201 nativeProperties
->staticAttributes
,
1202 nativeProperties
->staticAttributeIds
,
1203 nativeProperties
->staticAttributeSpecs
, desc
,
1207 if (desc
.object()) {
1212 if (nativeProperties
->attributes
) {
1213 if (!XrayResolveAttribute(cx
, wrapper
, obj
, id
,
1214 nativeProperties
->attributes
,
1215 nativeProperties
->attributeIds
,
1216 nativeProperties
->attributeSpecs
, desc
,
1220 if (desc
.object()) {
1226 if (nativeProperties
->constants
) {
1227 const Prefable
<const ConstantSpec
>* constant
;
1228 for (constant
= nativeProperties
->constants
; constant
->specs
; ++constant
) {
1229 if (constant
->isEnabled(cx
, obj
)) {
1230 // Set i to be the index into our full list of ids/specs that we're
1232 size_t i
= constant
->specs
- nativeProperties
->constantSpecs
;
1233 for ( ; nativeProperties
->constantIds
[i
] != JSID_VOID
; ++i
) {
1234 if (id
== nativeProperties
->constantIds
[i
]) {
1235 cacheOnHolder
= true;
1237 desc
.setAttributes(JSPROP_ENUMERATE
| JSPROP_READONLY
| JSPROP_PERMANENT
);
1238 desc
.object().set(wrapper
);
1239 desc
.value().set(nativeProperties
->constantSpecs
[i
].value
);
1251 ResolvePrototypeOrConstructor(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1252 JS::Handle
<JSObject
*> obj
,
1253 size_t protoAndIfaceCacheIndex
, unsigned attrs
,
1254 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1257 JS::Rooted
<JSObject
*> global(cx
, js::GetGlobalForObjectCrossCompartment(obj
));
1259 JSAutoCompartment
ac(cx
, global
);
1260 ProtoAndIfaceCache
& protoAndIfaceCache
= *GetProtoAndIfaceCache(global
);
1261 JSObject
* protoOrIface
=
1262 protoAndIfaceCache
.EntrySlotIfExists(protoAndIfaceCacheIndex
);
1263 if (!protoOrIface
) {
1267 cacheOnHolder
= true;
1269 desc
.object().set(wrapper
);
1270 desc
.setAttributes(attrs
);
1271 desc
.setGetter(JS_PropertyStub
);
1272 desc
.setSetter(JS_StrictPropertyStub
);
1273 desc
.value().set(JS::ObjectValue(*protoOrIface
));
1275 return JS_WrapPropertyDescriptor(cx
, desc
);
1279 XrayResolveNativeProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1280 const NativePropertyHooks
* nativePropertyHooks
,
1281 DOMObjectType type
, JS::Handle
<JSObject
*> obj
,
1282 JS::Handle
<jsid
> id
,
1283 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1284 bool& cacheOnHolder
)
1286 if (type
== eInterface
&& IdEquals(id
, "prototype")) {
1287 return nativePropertyHooks
->mPrototypeID
== prototypes::id::_ID_Count
||
1288 ResolvePrototypeOrConstructor(cx
, wrapper
, obj
,
1289 nativePropertyHooks
->mPrototypeID
,
1290 JSPROP_PERMANENT
| JSPROP_READONLY
,
1291 desc
, cacheOnHolder
);
1294 if (type
== eInterfacePrototype
&& IdEquals(id
, "constructor")) {
1295 return nativePropertyHooks
->mConstructorID
== constructors::id::_ID_Count
||
1296 ResolvePrototypeOrConstructor(cx
, wrapper
, obj
,
1297 nativePropertyHooks
->mConstructorID
,
1298 0, desc
, cacheOnHolder
);
1301 const NativePropertiesHolder
& nativeProperties
=
1302 nativePropertyHooks
->mNativeProperties
;
1304 if (nativeProperties
.regular
&&
1305 !XrayResolveProperty(cx
, wrapper
, obj
, id
, desc
, cacheOnHolder
, type
,
1306 nativeProperties
.regular
)) {
1310 if (!desc
.object() &&
1311 nativeProperties
.chromeOnly
&&
1312 xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper
)) &&
1313 !XrayResolveProperty(cx
, wrapper
, obj
, id
, desc
, cacheOnHolder
, type
,
1314 nativeProperties
.chromeOnly
)) {
1322 XrayResolveNativeProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1323 JS::Handle
<JSObject
*> obj
,
1324 JS::Handle
<jsid
> id
, JS::MutableHandle
<JSPropertyDescriptor
> desc
,
1325 bool& cacheOnHolder
)
1327 cacheOnHolder
= false;
1330 const NativePropertyHooks
* nativePropertyHooks
=
1331 GetNativePropertyHooks(cx
, obj
, type
);
1333 if (type
== eInstance
) {
1334 // Force the type to be eInterfacePrototype, since we need to walk the
1336 type
= eInterfacePrototype
;
1339 if (type
== eInterfacePrototype
) {
1341 if (!XrayResolveNativeProperty(cx
, wrapper
, nativePropertyHooks
, type
,
1342 obj
, id
, desc
, cacheOnHolder
)) {
1346 if (desc
.object()) {
1349 } while ((nativePropertyHooks
= nativePropertyHooks
->mProtoHooks
));
1354 return XrayResolveNativeProperty(cx
, wrapper
, nativePropertyHooks
, type
, obj
,
1355 id
, desc
, cacheOnHolder
);
1359 XrayDefineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1360 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
1361 JS::MutableHandle
<JSPropertyDescriptor
> desc
, bool* defined
)
1363 if (!js::IsProxy(obj
))
1366 const DOMProxyHandler
* handler
= GetDOMProxyHandler(obj
);
1367 return handler
->defineProperty(cx
, wrapper
, id
, desc
, defined
);
1370 template<typename SpecType
>
1372 XrayEnumerateAttributesOrMethods(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1373 JS::Handle
<JSObject
*> obj
,
1374 const Prefable
<const SpecType
>* list
,
1375 jsid
* ids
, const SpecType
* specList
,
1376 unsigned flags
, JS::AutoIdVector
& props
)
1378 for (; list
->specs
; ++list
) {
1379 if (list
->isEnabled(cx
, obj
)) {
1380 // Set i to be the index into our full list of ids/specs that we're
1382 size_t i
= list
->specs
- specList
;
1383 for ( ; ids
[i
] != JSID_VOID
; ++i
) {
1384 if (((flags
& JSITER_HIDDEN
) ||
1385 (specList
[i
].flags
& JSPROP_ENUMERATE
)) &&
1386 !props
.append(ids
[i
])) {
1395 #define ENUMERATE_IF_DEFINED(fieldName) { \
1396 if (nativeProperties->fieldName##s && \
1397 !XrayEnumerateAttributesOrMethods(cx, wrapper, obj, \
1398 nativeProperties->fieldName##s, \
1399 nativeProperties->fieldName##Ids, \
1400 nativeProperties->fieldName##Specs, \
1408 XrayEnumerateProperties(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1409 JS::Handle
<JSObject
*> obj
,
1410 unsigned flags
, JS::AutoIdVector
& props
,
1412 const NativeProperties
* nativeProperties
)
1414 if (type
== eInstance
) {
1415 ENUMERATE_IF_DEFINED(unforgeableMethod
);
1416 ENUMERATE_IF_DEFINED(unforgeableAttribute
);
1417 } else if (type
== eInterface
) {
1418 ENUMERATE_IF_DEFINED(staticMethod
);
1419 ENUMERATE_IF_DEFINED(staticAttribute
);
1421 MOZ_ASSERT(type
== eInterfacePrototype
);
1422 ENUMERATE_IF_DEFINED(method
);
1423 ENUMERATE_IF_DEFINED(attribute
);
1426 if (nativeProperties
->constants
) {
1427 const Prefable
<const ConstantSpec
>* constant
;
1428 for (constant
= nativeProperties
->constants
; constant
->specs
; ++constant
) {
1429 if (constant
->isEnabled(cx
, obj
)) {
1430 // Set i to be the index into our full list of ids/specs that we're
1432 size_t i
= constant
->specs
- nativeProperties
->constantSpecs
;
1433 for ( ; nativeProperties
->constantIds
[i
] != JSID_VOID
; ++i
) {
1434 if (!props
.append(nativeProperties
->constantIds
[i
])) {
1445 #undef ENUMERATE_IF_DEFINED
1448 XrayEnumerateNativeProperties(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1449 const NativePropertyHooks
* nativePropertyHooks
,
1450 DOMObjectType type
, JS::Handle
<JSObject
*> obj
,
1451 unsigned flags
, JS::AutoIdVector
& props
)
1453 if (type
== eInterface
&&
1454 nativePropertyHooks
->mPrototypeID
!= prototypes::id::_ID_Count
&&
1455 !AddStringToIDVector(cx
, props
, "prototype")) {
1459 if (type
== eInterfacePrototype
&&
1460 nativePropertyHooks
->mConstructorID
!= constructors::id::_ID_Count
&&
1461 (flags
& JSITER_HIDDEN
) &&
1462 !AddStringToIDVector(cx
, props
, "constructor")) {
1466 const NativePropertiesHolder
& nativeProperties
=
1467 nativePropertyHooks
->mNativeProperties
;
1469 if (nativeProperties
.regular
&&
1470 !XrayEnumerateProperties(cx
, wrapper
, obj
, flags
, props
, type
,
1471 nativeProperties
.regular
)) {
1475 if (nativeProperties
.chromeOnly
&&
1476 xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper
)) &&
1477 !XrayEnumerateProperties(cx
, wrapper
, obj
, flags
, props
, type
,
1478 nativeProperties
.chromeOnly
)) {
1486 XrayEnumerateProperties(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1487 JS::Handle
<JSObject
*> obj
,
1488 unsigned flags
, JS::AutoIdVector
& props
)
1491 const NativePropertyHooks
* nativePropertyHooks
=
1492 GetNativePropertyHooks(cx
, obj
, type
);
1494 if (type
== eInstance
) {
1495 if (nativePropertyHooks
->mEnumerateOwnProperties
&&
1496 !nativePropertyHooks
->mEnumerateOwnProperties(cx
, wrapper
, obj
,
1501 // Handle Unforgeable properties.
1502 if (!XrayEnumerateNativeProperties(cx
, wrapper
, nativePropertyHooks
, type
,
1503 obj
, flags
, props
)) {
1507 if (flags
& JSITER_OWNONLY
) {
1511 // Force the type to be eInterfacePrototype, since we need to walk the
1513 type
= eInterfacePrototype
;
1516 if (type
== eInterfacePrototype
) {
1518 if (!XrayEnumerateNativeProperties(cx
, wrapper
, nativePropertyHooks
, type
,
1519 obj
, flags
, props
)) {
1523 if (flags
& JSITER_OWNONLY
) {
1526 } while ((nativePropertyHooks
= nativePropertyHooks
->mProtoHooks
));
1531 return XrayEnumerateNativeProperties(cx
, wrapper
, nativePropertyHooks
, type
,
1535 NativePropertyHooks sWorkerNativePropertyHooks
= {
1542 prototypes::id::_ID_Count
,
1543 constructors::id::_ID_Count
,
1548 GetPropertyOnPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1549 JS::Handle
<jsid
> id
, bool* found
,
1552 JS::Rooted
<JSObject
*> proto(cx
);
1553 if (!js::GetObjectProto(cx
, proxy
, &proto
)) {
1562 if (!JS_HasPropertyById(cx
, proto
, id
, &hasProp
)) {
1567 if (!hasProp
|| !vp
) {
1571 JS::Rooted
<JS::Value
> value(cx
);
1572 if (!JS_ForwardGetPropertyTo(cx
, proto
, id
, proxy
, &value
)) {
1581 HasPropertyOnPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1582 JS::Handle
<jsid
> id
)
1584 JS::Rooted
<JSObject
*> curr(cx
, proxy
);
1586 JS::Rooted
<JSObject
*> proto(cx
);
1587 if (!js::GetObjectProto(cx
, curr
, &proto
)) {
1588 JS_ClearPendingException(cx
);
1589 return true; // Fail safe.
1597 if (!JS_HasPropertyById(cx
, proto
, id
, &hasProp
)) {
1598 JS_ClearPendingException(cx
);
1599 return true; // Fail safe.
1611 AppendNamedPropertyIds(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1612 nsTArray
<nsString
>& names
,
1613 bool shadowPrototypeProperties
,
1614 JS::AutoIdVector
& props
)
1616 for (uint32_t i
= 0; i
< names
.Length(); ++i
) {
1617 JS::Rooted
<JS::Value
> v(cx
);
1618 if (!xpc::NonVoidStringToJsval(cx
, names
[i
], &v
)) {
1622 JS::Rooted
<jsid
> id(cx
);
1623 if (!JS_ValueToId(cx
, v
, &id
)) {
1627 if (shadowPrototypeProperties
|| !HasPropertyOnPrototype(cx
, proxy
, id
)) {
1628 if (!props
.append(id
)) {
1638 DictionaryBase::ParseJSON(JSContext
* aCx
,
1639 const nsAString
& aJSON
,
1640 JS::MutableHandle
<JS::Value
> aVal
)
1642 if (aJSON
.IsEmpty()) {
1645 return JS_ParseJSON(aCx
,
1646 static_cast<const jschar
*>(PromiseFlatString(aJSON
).get()),
1647 aJSON
.Length(), aVal
);
1651 DictionaryBase::StringifyToJSON(JSContext
* aCx
,
1652 JS::MutableHandle
<JS::Value
> aValue
,
1655 return JS_Stringify(aCx
, aValue
, JS::NullPtr(), JS::NullHandleValue
,
1656 AppendJSONToString
, &aJSON
);
1661 DictionaryBase::AppendJSONToString(const jschar
* aJSONData
,
1662 uint32_t aDataLength
,
1665 nsAString
* string
= static_cast<nsAString
*>(aString
);
1666 string
->Append(static_cast<const char16_t
*>(aJSONData
),
1674 ConcatJSString(JSContext
* cx
, const char* pre
, JS::Handle
<JSString
*> str
, const char* post
)
1680 JS::Rooted
<JSString
*> preString(cx
, JS_NewStringCopyN(cx
, pre
, strlen(pre
)));
1681 JS::Rooted
<JSString
*> postString(cx
, JS_NewStringCopyN(cx
, post
, strlen(post
)));
1682 if (!preString
|| !postString
) {
1686 preString
= JS_ConcatStrings(cx
, preString
, str
);
1691 return JS_ConcatStrings(cx
, preString
, postString
);
1695 NativeToString(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
1696 JS::Handle
<JSObject
*> obj
,
1697 JS::MutableHandle
<JS::Value
> v
)
1699 JS::Rooted
<JSPropertyDescriptor
> toStringDesc(cx
);
1700 toStringDesc
.object().set(nullptr);
1701 toStringDesc
.setAttributes(0);
1702 toStringDesc
.setGetter(nullptr);
1703 toStringDesc
.setSetter(nullptr);
1704 toStringDesc
.value().set(JS::UndefinedValue());
1705 JS::Rooted
<jsid
> id(cx
,
1706 nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING
));
1708 if (!XrayResolveNativeProperty(cx
, wrapper
, obj
, id
, &toStringDesc
, unused
)) {
1712 JS::Rooted
<JSString
*> str(cx
);
1714 JSAutoCompartment
ac(cx
, obj
);
1715 if (toStringDesc
.object()) {
1716 JS::Rooted
<JS::Value
> toString(cx
, toStringDesc
.value());
1717 if (!JS_WrapValue(cx
, &toString
)) {
1720 MOZ_ASSERT(JS_ObjectIsCallable(cx
, &toString
.toObject()));
1721 JS::Rooted
<JS::Value
> toStringResult(cx
);
1722 if (JS_CallFunctionValue(cx
, obj
, toString
, JS::HandleValueArray::empty(),
1724 str
= toStringResult
.toString();
1729 const js::Class
* clasp
= js::GetObjectClass(obj
);
1730 if (IsDOMClass(clasp
)) {
1731 str
= JS_NewStringCopyZ(cx
, clasp
->name
);
1732 str
= ConcatJSString(cx
, "[object ", str
, "]");
1733 } else if (IsDOMIfaceAndProtoClass(clasp
)) {
1734 const DOMIfaceAndProtoJSClass
* ifaceAndProtoJSClass
=
1735 DOMIfaceAndProtoJSClass::FromJSClass(clasp
);
1736 str
= JS_NewStringCopyZ(cx
, ifaceAndProtoJSClass
->mToString
);
1738 MOZ_ASSERT(JS_IsNativeFunction(obj
, Constructor
));
1739 JS::Rooted
<JSFunction
*> fun(cx
, JS_GetObjectFunction(obj
));
1740 str
= JS_DecompileFunction(cx
, fun
, 0);
1750 return JS_WrapValue(cx
, v
);
1753 // Dynamically ensure that two objects don't end up with the same reserved slot.
1754 class MOZ_STACK_CLASS AutoCloneDOMObjectSlotGuard
1757 AutoCloneDOMObjectSlotGuard(JSContext
* aCx
, JSObject
* aOld
, JSObject
* aNew
)
1758 : mOldReflector(aCx
, aOld
), mNewReflector(aCx
, aNew
)
1760 MOZ_ASSERT(js::GetReservedSlot(aOld
, DOM_OBJECT_SLOT
) ==
1761 js::GetReservedSlot(aNew
, DOM_OBJECT_SLOT
));
1764 ~AutoCloneDOMObjectSlotGuard()
1766 if (js::GetReservedSlot(mOldReflector
, DOM_OBJECT_SLOT
).toPrivate()) {
1767 js::SetReservedSlot(mNewReflector
, DOM_OBJECT_SLOT
,
1768 JS::PrivateValue(nullptr));
1773 JS::Rooted
<JSObject
*> mOldReflector
;
1774 JS::Rooted
<JSObject
*> mNewReflector
;
1778 ReparentWrapper(JSContext
* aCx
, JS::Handle
<JSObject
*> aObjArg
)
1780 js::AssertSameCompartment(aCx
, aObjArg
);
1782 // Check if we're anywhere near the stack limit before we reach the
1783 // transplanting code, since it has no good way to handle errors. This uses
1784 // the untrusted script limit, which is not strictly necessary since no
1785 // actual script should run.
1786 JS_CHECK_RECURSION_CONSERVATIVE(aCx
, return NS_ERROR_FAILURE
);
1788 JS::Rooted
<JSObject
*> aObj(aCx
, aObjArg
);
1789 const DOMJSClass
* domClass
= GetDOMClass(aObj
);
1791 JS::Rooted
<JSObject
*> oldParent(aCx
, JS_GetParent(aObj
));
1792 JS::Rooted
<JSObject
*> newParent(aCx
, domClass
->mGetParent(aCx
, aObj
));
1794 JSAutoCompartment
oldAc(aCx
, oldParent
);
1796 JSCompartment
* oldCompartment
= js::GetObjectCompartment(oldParent
);
1797 JSCompartment
* newCompartment
= js::GetObjectCompartment(newParent
);
1798 if (oldCompartment
== newCompartment
) {
1799 if (!JS_SetParent(aCx
, aObj
, newParent
)) {
1805 nsISupports
* native
= UnwrapDOMObjectToISupports(aObj
);
1810 bool isProxy
= js::IsProxy(aObj
);
1811 JS::Rooted
<JSObject
*> expandoObject(aCx
);
1813 expandoObject
= DOMProxyHandler::GetAndClearExpandoObject(aObj
);
1816 JSAutoCompartment
newAc(aCx
, newParent
);
1818 // First we clone the reflector. We get a copy of its properties and clone its
1819 // expando chain. The only part that is dangerous here is that if we have to
1820 // return early we must avoid ending up with two reflectors pointing to the
1821 // same native. Other than that, the objects we create will just go away.
1823 JS::Rooted
<JSObject
*> global(aCx
,
1824 js::GetGlobalForObjectCrossCompartment(newParent
));
1825 JS::Handle
<JSObject
*> proto
= (domClass
->mGetProto
)(aCx
, global
);
1827 return NS_ERROR_FAILURE
;
1830 JS::Rooted
<JSObject
*> newobj(aCx
, JS_CloneObject(aCx
, aObj
, proto
, newParent
));
1832 return NS_ERROR_FAILURE
;
1835 js::SetReservedSlot(newobj
, DOM_OBJECT_SLOT
,
1836 js::GetReservedSlot(aObj
, DOM_OBJECT_SLOT
));
1838 // At this point, both |aObj| and |newobj| point to the same native
1839 // which is bad, because one of them will end up being finalized with a
1840 // native it does not own. |cloneGuard| ensures that if we exit before
1841 // clearing |aObj|'s reserved slot the reserved slot of |newobj| will be
1842 // set to null. |aObj| will go away soon, because we swap it with
1843 // another object during the transplant and let that object die.
1844 JS::Rooted
<JSObject
*> propertyHolder(aCx
);
1846 AutoCloneDOMObjectSlotGuard
cloneGuard(aCx
, aObj
, newobj
);
1848 JS::Rooted
<JSObject
*> copyFrom(aCx
, isProxy
? expandoObject
: aObj
);
1850 propertyHolder
= JS_NewObjectWithGivenProto(aCx
, nullptr, JS::NullPtr(),
1852 if (!propertyHolder
) {
1853 return NS_ERROR_OUT_OF_MEMORY
;
1856 if (!JS_CopyPropertiesFrom(aCx
, propertyHolder
, copyFrom
)) {
1857 return NS_ERROR_FAILURE
;
1860 propertyHolder
= nullptr;
1863 // Expandos from other compartments are attached to the target JS object.
1864 // Copy them over, and let the old ones die a natural death.
1865 if (!xpc::XrayUtils::CloneExpandoChain(aCx
, newobj
, aObj
)) {
1866 return NS_ERROR_FAILURE
;
1869 // We've set up |newobj|, so we make it own the native by nulling
1870 // out the reserved slot of |obj|.
1872 // NB: It's important to do this _after_ copying the properties to
1873 // propertyHolder. Otherwise, an object with |foo.x === foo| will
1874 // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
1875 js::SetReservedSlot(aObj
, DOM_OBJECT_SLOT
, JS::PrivateValue(nullptr));
1878 aObj
= xpc::TransplantObject(aCx
, aObj
, newobj
);
1883 nsWrapperCache
* cache
= nullptr;
1884 CallQueryInterface(native
, &cache
);
1885 bool preserving
= cache
->PreservingWrapper();
1886 cache
->SetPreservingWrapper(false);
1887 cache
->SetWrapper(aObj
);
1888 cache
->SetPreservingWrapper(preserving
);
1890 if (propertyHolder
) {
1891 JS::Rooted
<JSObject
*> copyTo(aCx
);
1893 copyTo
= DOMProxyHandler::EnsureExpandoObject(aCx
, aObj
);
1898 if (!copyTo
|| !JS_CopyPropertiesFrom(aCx
, copyTo
, propertyHolder
)) {
1903 nsObjectLoadingContent
* htmlobject
;
1904 nsresult rv
= UNWRAP_OBJECT(HTMLObjectElement
, aObj
, htmlobject
);
1905 if (NS_FAILED(rv
)) {
1906 rv
= UnwrapObject
<prototypes::id::HTMLEmbedElement
,
1907 HTMLSharedObjectElement
>(aObj
, htmlobject
);
1908 if (NS_FAILED(rv
)) {
1909 rv
= UnwrapObject
<prototypes::id::HTMLAppletElement
,
1910 HTMLSharedObjectElement
>(aObj
, htmlobject
);
1911 if (NS_FAILED(rv
)) {
1912 htmlobject
= nullptr;
1917 htmlobject
->SetupProtoChain(aCx
, aObj
);
1920 // Now we can just fix up the parent and return the wrapper
1922 if (newParent
&& !JS_SetParent(aCx
, aObj
, newParent
)) {
1929 GlobalObject::GlobalObject(JSContext
* aCx
, JSObject
* aObject
)
1930 : mGlobalJSObject(aCx
),
1932 mGlobalObject(nullptr)
1935 JS::Rooted
<JSObject
*> obj(aCx
, aObject
);
1936 if (js::IsWrapper(obj
)) {
1937 obj
= js::CheckedUnwrap(obj
, /* stopAtOuter = */ false);
1939 // We should never end up here on a worker thread, since there shouldn't
1940 // be any security wrappers to worry about.
1941 if (!MOZ_LIKELY(NS_IsMainThread())) {
1945 Throw(aCx
, NS_ERROR_XPC_SECURITY_MANAGER_VETO
);
1950 mGlobalJSObject
= js::GetGlobalForObjectCrossCompartment(obj
);
1954 GlobalObject::GetAsSupports() const
1956 if (mGlobalObject
) {
1957 return mGlobalObject
;
1960 if (!NS_IsMainThread()) {
1961 mGlobalObject
= UnwrapDOMObjectToISupports(mGlobalJSObject
);
1962 return mGlobalObject
;
1965 JS::Rooted
<JS::Value
> val(mCx
, JS::ObjectValue(*mGlobalJSObject
));
1967 // Switch this to UnwrapDOMObjectToISupports once our global objects are
1968 // using new bindings.
1969 nsresult rv
= xpc_qsUnwrapArg
<nsISupports
>(mCx
, val
, &mGlobalObject
,
1970 static_cast<nsISupports
**>(getter_AddRefs(mGlobalObjectRef
)),
1972 if (NS_FAILED(rv
)) {
1973 mGlobalObject
= nullptr;
1974 Throw(mCx
, NS_ERROR_XPC_BAD_CONVERT_JS
);
1977 return mGlobalObject
;
1981 InterfaceHasInstance(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
1982 JS::Handle
<JSObject
*> instance
,
1985 const DOMIfaceAndProtoJSClass
* clasp
=
1986 DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj
));
1988 const DOMJSClass
* domClass
= GetDOMClass(js::UncheckedUnwrap(instance
, /* stopAtOuter = */ false));
1990 MOZ_ASSERT(!domClass
|| clasp
->mPrototypeID
!= prototypes::id::_ID_Count
,
1991 "Why do we have a hasInstance hook if we don't have a prototype "
1995 domClass
->mInterfaceChain
[clasp
->mDepth
] == clasp
->mPrototypeID
) {
2000 if (jsipc::IsWrappedCPOW(instance
)) {
2002 if (!jsipc::DOMInstanceOf(cx
, js::CheckedUnwrap(instance
), clasp
->mPrototypeID
,
2003 clasp
->mDepth
, &boolp
)) {
2010 JS::Rooted
<JS::Value
> protov(cx
);
2011 DebugOnly
<bool> ok
= JS_GetProperty(cx
, obj
, "prototype", &protov
);
2012 MOZ_ASSERT(ok
, "Someone messed with our prototype property?");
2014 JS::Rooted
<JSObject
*> interfacePrototype(cx
, &protov
.toObject());
2015 MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype
)),
2016 "Someone messed with our prototype property?");
2018 JS::Rooted
<JSObject
*> proto(cx
);
2019 if (!JS_GetPrototype(cx
, instance
, &proto
)) {
2024 if (proto
== interfacePrototype
) {
2029 if (!JS_GetPrototype(cx
, proto
, &proto
)) {
2039 InterfaceHasInstance(JSContext
* cx
, JS::Handle
<JSObject
*> obj
, JS::MutableHandle
<JS::Value
> vp
,
2042 if (!vp
.isObject()) {
2047 JS::Rooted
<JSObject
*> instanceObject(cx
, &vp
.toObject());
2048 return InterfaceHasInstance(cx
, obj
, instanceObject
, bp
);
2052 InterfaceHasInstance(JSContext
* cx
, int prototypeID
, int depth
,
2053 JS::Handle
<JSObject
*> instance
,
2056 const DOMJSClass
* domClass
= GetDOMClass(js::UncheckedUnwrap(instance
));
2058 MOZ_ASSERT(!domClass
|| prototypeID
!= prototypes::id::_ID_Count
,
2059 "Why do we have a hasInstance hook if we don't have a prototype "
2062 *bp
= (domClass
&& domClass
->mInterfaceChain
[depth
] == prototypeID
);
2067 ReportLenientThisUnwrappingFailure(JSContext
* cx
, JSObject
* obj
)
2069 JS::Rooted
<JSObject
*> rootedObj(cx
, obj
);
2070 GlobalObject
global(cx
, rootedObj
);
2071 if (global
.Failed()) {
2074 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(global
.GetAsSupports());
2075 if (window
&& window
->GetDoc()) {
2076 window
->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis
);
2082 GetWindowForJSImplementedObject(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
2083 nsPIDOMWindow
** window
)
2085 // Be very careful to not get tricked here.
2086 MOZ_ASSERT(NS_IsMainThread());
2087 if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj
))) {
2088 NS_RUNTIMEABORT("Should have a chrome object here");
2091 // Look up the content-side object.
2092 JS::Rooted
<JS::Value
> domImplVal(cx
);
2093 if (!JS_GetProperty(cx
, obj
, "__DOM_IMPL__", &domImplVal
)) {
2097 if (!domImplVal
.isObject()) {
2098 ThrowErrorMessage(cx
, MSG_NOT_OBJECT
, "Value");
2102 // Go ahead and get the global from it. GlobalObject will handle
2103 // doing unwrapping as needed.
2104 GlobalObject
global(cx
, &domImplVal
.toObject());
2105 if (global
.Failed()) {
2109 // It's OK if we have null here: that just means the content-side
2110 // object really wasn't associated with any window.
2111 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(global
.GetAsSupports()));
2116 already_AddRefed
<nsPIDOMWindow
>
2117 ConstructJSImplementation(JSContext
* aCx
, const char* aContractId
,
2118 const GlobalObject
& aGlobal
,
2119 JS::MutableHandle
<JSObject
*> aObject
,
2122 // Get the window to use as a parent and for initialization.
2123 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(aGlobal
.GetAsSupports());
2125 aRv
.Throw(NS_ERROR_FAILURE
);
2129 ConstructJSImplementation(aCx
, aContractId
, window
, aObject
, aRv
);
2134 return window
.forget();
2138 ConstructJSImplementation(JSContext
* aCx
, const char* aContractId
,
2139 nsPIDOMWindow
* aWindow
,
2140 JS::MutableHandle
<JSObject
*> aObject
,
2143 // Make sure to divorce ourselves from the calling JS while creating and
2144 // initializing the object, so exceptions from that will get reported
2145 // properly, since those are never exceptions that a spec wants to be thrown.
2147 AutoNoJSAPI nojsapi
;
2149 // Get the XPCOM component containing the JS implementation.
2150 nsCOMPtr
<nsISupports
> implISupports
= do_CreateInstance(aContractId
);
2151 if (!implISupports
) {
2152 NS_WARNING("Failed to get JS implementation for contract");
2153 aRv
.Throw(NS_ERROR_FAILURE
);
2156 // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer.
2157 nsCOMPtr
<nsIDOMGlobalPropertyInitializer
> gpi
=
2158 do_QueryInterface(implISupports
);
2160 JS::Rooted
<JS::Value
> initReturn(aCx
);
2161 nsresult rv
= gpi
->Init(aWindow
, &initReturn
);
2162 if (NS_FAILED(rv
)) {
2166 // With JS-implemented WebIDL, the return value of init() is not used to determine
2167 // if init() failed, so init() should only return undefined. Any kind of permission
2168 // or pref checking must happen by adding an attribute to the WebIDL interface.
2169 if (!initReturn
.isUndefined()) {
2170 MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
2174 // Extract the JS implementation from the XPCOM object.
2175 nsCOMPtr
<nsIXPConnectWrappedJS
> implWrapped
=
2176 do_QueryInterface(implISupports
);
2177 MOZ_ASSERT(implWrapped
, "Failed to get wrapped JS from XPCOM component.");
2179 aRv
.Throw(NS_ERROR_FAILURE
);
2182 aObject
.set(implWrapped
->GetJSObject());
2184 aRv
.Throw(NS_ERROR_FAILURE
);
2190 NonVoidByteStringToJsval(JSContext
*cx
, const nsACString
&str
,
2191 JS::MutableHandle
<JS::Value
> rval
)
2193 // ByteStrings are not UTF-8 encoded.
2194 JSString
* jsStr
= JS_NewStringCopyN(cx
, str
.Data(), str
.Length());
2199 rval
.setString(jsStr
);
2204 template<typename T
> static void
2205 NormalizeScalarValueStringInternal(JSContext
* aCx
, T
& aString
)
2207 char16_t
* start
= aString
.BeginWriting();
2208 // Must use const here because we can't pass char** to UTF16CharEnumerator as
2209 // it expects const char**. Unclear why this is illegal...
2210 const char16_t
* nextChar
= start
;
2211 const char16_t
* end
= aString
.Data() + aString
.Length();
2212 while (nextChar
< end
) {
2213 uint32_t enumerated
= UTF16CharEnumerator::NextChar(&nextChar
, end
);
2214 if (enumerated
== UCS2_REPLACEMENT_CHAR
) {
2215 int32_t lastCharIndex
= (nextChar
- start
) - 1;
2216 start
[lastCharIndex
] = static_cast<char16_t
>(enumerated
);
2222 NormalizeScalarValueString(JSContext
* aCx
, nsAString
& aString
)
2224 NormalizeScalarValueStringInternal(aCx
, aString
);
2228 NormalizeScalarValueString(JSContext
* aCx
, binding_detail::FakeString
& aString
)
2230 NormalizeScalarValueStringInternal(aCx
, aString
);
2234 ConvertJSValueToByteString(JSContext
* cx
, JS::Handle
<JS::Value
> v
,
2235 bool nullable
, nsACString
& result
)
2237 JS::Rooted
<JSString
*> s(cx
);
2242 if (nullable
&& v
.isNullOrUndefined()) {
2243 result
.SetIsVoid(true);
2247 s
= JS::ToString(cx
, v
);
2253 // Conversion from Javascript string to ByteString is only valid if all
2254 // characters < 256. This is always the case for Latin1 strings.
2256 if (!js::StringHasLatin1Chars(s
)) {
2257 // ThrowErrorMessage can GC, so we first scan the string for bad chars
2258 // and report the error outside the AutoCheckCannotGC scope.
2259 bool foundBadChar
= false;
2260 size_t badCharIndex
;
2263 JS::AutoCheckCannotGC nogc
;
2264 const jschar
* chars
= JS_GetTwoByteStringCharsAndLength(cx
, nogc
, s
, &length
);
2269 for (size_t i
= 0; i
< length
; i
++) {
2270 if (chars
[i
] > 255) {
2273 foundBadChar
= true;
2280 MOZ_ASSERT(badCharIndex
< length
);
2281 MOZ_ASSERT(badChar
> 255);
2282 // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
2283 // 20 digits, plus one more for the null terminator.
2285 static_assert(sizeof(size_t) <= 8, "index array too small");
2286 PR_snprintf(index
, sizeof(index
), "%d", badCharIndex
);
2287 // A jschar is 16 bits long. The biggest unsigned 16 bit
2288 // number (65,535) has 5 digits, plus one more for the null
2290 char badCharArray
[6];
2291 static_assert(sizeof(jschar
) <= 2, "badCharArray too small");
2292 PR_snprintf(badCharArray
, sizeof(badCharArray
), "%d", badChar
);
2293 ThrowErrorMessage(cx
, MSG_INVALID_BYTESTRING
, index
, badCharArray
);
2297 length
= js::GetStringLength(s
);
2300 static_assert(js::MaxStringLength
< UINT32_MAX
,
2301 "length+1 shouldn't overflow");
2303 result
.SetLength(length
);
2304 JS_EncodeStringToBuffer(cx
, s
, result
.BeginWriting(), length
);
2310 IsInPrivilegedApp(JSContext
* aCx
, JSObject
* aObj
)
2312 using mozilla::dom::workers::GetWorkerPrivateFromContext
;
2313 if (!NS_IsMainThread()) {
2314 return GetWorkerPrivateFromContext(aCx
)->IsInPrivilegedApp();
2317 nsIPrincipal
* principal
= nsContentUtils::ObjectPrincipal(aObj
);
2318 uint16_t appStatus
= principal
->GetAppStatus();
2319 return (appStatus
== nsIPrincipal::APP_STATUS_CERTIFIED
||
2320 appStatus
== nsIPrincipal::APP_STATUS_PRIVILEGED
) ||
2321 Preferences::GetBool("dom.ignore_webidl_scope_checks", false);
2325 IsInCertifiedApp(JSContext
* aCx
, JSObject
* aObj
)
2327 using mozilla::dom::workers::GetWorkerPrivateFromContext
;
2328 if (!NS_IsMainThread()) {
2329 return GetWorkerPrivateFromContext(aCx
)->IsInCertifiedApp();
2332 nsIPrincipal
* principal
= nsContentUtils::ObjectPrincipal(aObj
);
2333 return principal
->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED
||
2334 Preferences::GetBool("dom.ignore_webidl_scope_checks", false);
2339 VerifyTraceProtoAndIfaceCacheCalled(JSTracer
*trc
, void **thingp
,
2342 // We don't do anything here, we only want to verify that
2343 // TraceProtoAndIfaceCache was called.
2348 FinalizeGlobal(JSFreeOp
* aFreeOp
, JSObject
* aObj
)
2350 MOZ_ASSERT(js::GetObjectClass(aObj
)->flags
& JSCLASS_DOM_GLOBAL
);
2351 mozilla::dom::DestroyProtoAndIfaceCache(aObj
);
2355 ResolveGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
2356 JS::Handle
<jsid
> aId
, JS::MutableHandle
<JSObject
*> aObjp
)
2359 if (!JS_ResolveStandardClass(aCx
, aObj
, aId
, &resolved
)) {
2363 aObjp
.set(resolved
? aObj
.get() : nullptr);
2368 EnumerateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
)
2370 return JS_EnumerateStandardClasses(aCx
, aObj
);
2374 CheckPermissions(JSContext
* aCx
, JSObject
* aObj
, const char* const aPermissions
[])
2376 JS::Rooted
<JSObject
*> rootedObj(aCx
, aObj
);
2377 nsPIDOMWindow
* window
= xpc::WindowGlobalOrNull(rootedObj
);
2382 nsCOMPtr
<nsIPermissionManager
> permMgr
= services::GetPermissionManager();
2383 NS_ENSURE_TRUE(permMgr
, false);
2386 uint32_t permission
= nsIPermissionManager::DENY_ACTION
;
2387 permMgr
->TestPermissionFromWindow(window
, *aPermissions
, &permission
);
2388 if (permission
== nsIPermissionManager::ALLOW_ACTION
) {
2391 } while (*(++aPermissions
));
2396 CheckSafetyInPrerendering(JSContext
* aCx
, JSObject
* aObj
)
2398 //TODO: Check if page is being prerendered.
2399 //Returning false for now.
2404 GenericBindingGetter(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
2406 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
2407 const JSJitInfo
*info
= FUNCTION_VALUE_TO_JITINFO(args
.calleev());
2408 prototypes::ID protoID
= static_cast<prototypes::ID
>(info
->protoID
);
2409 if (!args
.thisv().isObject()) {
2410 return ThrowInvalidThis(cx
, args
,
2411 MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE
,
2414 JS::Rooted
<JSObject
*> obj(cx
, &args
.thisv().toObject());
2418 nsresult rv
= UnwrapObject
<void>(obj
, self
, protoID
, info
->depth
);
2419 if (NS_FAILED(rv
)) {
2420 return ThrowInvalidThis(cx
, args
,
2421 GetInvalidThisErrorForGetter(rv
== NS_ERROR_XPC_SECURITY_MANAGER_VETO
),
2426 MOZ_ASSERT(info
->type() == JSJitInfo::Getter
);
2427 JSJitGetterOp getter
= info
->getter
;
2428 bool ok
= getter(cx
, obj
, self
, JSJitGetterCallArgs(args
));
2431 AssertReturnTypeMatchesJitinfo(info
, args
.rval());
2438 GenericBindingSetter(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
2440 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
2441 const JSJitInfo
*info
= FUNCTION_VALUE_TO_JITINFO(args
.calleev());
2442 prototypes::ID protoID
= static_cast<prototypes::ID
>(info
->protoID
);
2443 if (!args
.thisv().isObject()) {
2444 return ThrowInvalidThis(cx
, args
,
2445 MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE
,
2448 JS::Rooted
<JSObject
*> obj(cx
, &args
.thisv().toObject());
2452 nsresult rv
= UnwrapObject
<void>(obj
, self
, protoID
, info
->depth
);
2453 if (NS_FAILED(rv
)) {
2454 return ThrowInvalidThis(cx
, args
,
2455 GetInvalidThisErrorForSetter(rv
== NS_ERROR_XPC_SECURITY_MANAGER_VETO
),
2459 if (args
.length() == 0) {
2460 return ThrowNoSetterArg(cx
, protoID
);
2462 MOZ_ASSERT(info
->type() == JSJitInfo::Setter
);
2463 JSJitSetterOp setter
= info
->setter
;
2464 if (!setter(cx
, obj
, self
, JSJitSetterCallArgs(args
))) {
2467 args
.rval().setUndefined();
2469 AssertReturnTypeMatchesJitinfo(info
, args
.rval());
2475 GenericBindingMethod(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
2477 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
2478 const JSJitInfo
*info
= FUNCTION_VALUE_TO_JITINFO(args
.calleev());
2479 prototypes::ID protoID
= static_cast<prototypes::ID
>(info
->protoID
);
2480 if (!args
.thisv().isObject()) {
2481 return ThrowInvalidThis(cx
, args
,
2482 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE
,
2485 JS::Rooted
<JSObject
*> obj(cx
, &args
.thisv().toObject());
2489 nsresult rv
= UnwrapObject
<void>(obj
, self
, protoID
, info
->depth
);
2490 if (NS_FAILED(rv
)) {
2491 return ThrowInvalidThis(cx
, args
,
2492 GetInvalidThisErrorForMethod(rv
== NS_ERROR_XPC_SECURITY_MANAGER_VETO
),
2496 MOZ_ASSERT(info
->type() == JSJitInfo::Method
);
2497 JSJitMethodOp method
= info
->method
;
2498 bool ok
= method(cx
, obj
, self
, JSJitMethodCallArgs(args
));
2501 AssertReturnTypeMatchesJitinfo(info
, args
.rval());
2508 GenericPromiseReturningBindingMethod(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
2510 // Make sure to save the callee before someone maybe messes with rval().
2511 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
2512 JS::Rooted
<JSObject
*> callee(cx
, &args
.callee());
2514 // We could invoke GenericBindingMethod here, but that involves an
2515 // extra call. Manually inline it instead.
2516 const JSJitInfo
*info
= FUNCTION_VALUE_TO_JITINFO(args
.calleev());
2517 prototypes::ID protoID
= static_cast<prototypes::ID
>(info
->protoID
);
2518 if (!args
.thisv().isObject()) {
2519 ThrowInvalidThis(cx
, args
,
2520 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE
,
2522 return ConvertExceptionToPromise(cx
, xpc::XrayAwareCalleeGlobal(callee
),
2525 JS::Rooted
<JSObject
*> obj(cx
, &args
.thisv().toObject());
2529 nsresult rv
= UnwrapObject
<void>(obj
, self
, protoID
, info
->depth
);
2530 if (NS_FAILED(rv
)) {
2531 ThrowInvalidThis(cx
, args
,
2532 GetInvalidThisErrorForMethod(rv
== NS_ERROR_XPC_SECURITY_MANAGER_VETO
),
2534 return ConvertExceptionToPromise(cx
, xpc::XrayAwareCalleeGlobal(callee
),
2538 MOZ_ASSERT(info
->type() == JSJitInfo::Method
);
2539 JSJitMethodOp method
= info
->method
;
2540 bool ok
= method(cx
, obj
, self
, JSJitMethodCallArgs(args
));
2543 AssertReturnTypeMatchesJitinfo(info
, args
.rval());
2548 // Promise-returning methods always return objects
2549 MOZ_ASSERT(info
->returnType() == JSVAL_TYPE_OBJECT
);
2550 return ConvertExceptionToPromise(cx
, xpc::XrayAwareCalleeGlobal(callee
),
2555 StaticMethodPromiseWrapper(JSContext
* cx
, unsigned argc
, JS::Value
* vp
)
2557 // Make sure to save the callee before someone maybe messes with rval().
2558 JS::CallArgs args
= JS::CallArgsFromVp(argc
, vp
);
2559 JS::Rooted
<JSObject
*> callee(cx
, &args
.callee());
2561 const JSJitInfo
*info
= FUNCTION_VALUE_TO_JITINFO(args
.calleev());
2563 MOZ_ASSERT(info
->type() == JSJitInfo::StaticMethod
);
2565 bool ok
= info
->staticMethod(cx
, argc
, vp
);
2570 return ConvertExceptionToPromise(cx
, xpc::XrayAwareCalleeGlobal(callee
),
2575 ConvertExceptionToPromise(JSContext
* cx
,
2576 JSObject
* promiseScope
,
2577 JS::MutableHandle
<JS::Value
> rval
)
2579 GlobalObject
global(cx
, promiseScope
);
2580 if (global
.Failed()) {
2584 JS::Rooted
<JS::Value
> exn(cx
);
2585 if (!JS_GetPendingException(cx
, &exn
)) {
2589 JS_ClearPendingException(cx
);
2591 nsRefPtr
<Promise
> promise
= Promise::Reject(global
, exn
, rv
);
2593 // We just give up. Make sure to not leak memory on the
2594 // ErrorResult, but then just put the original exception back.
2595 ThrowMethodFailedWithDetails(cx
, rv
, "", "");
2596 JS_SetPendingException(cx
, exn
);
2600 return WrapNewBindingObject(cx
, promise
, rval
);
2605 CreateGlobalOptions
<nsGlobalWindow
>::TraceGlobal(JSTracer
* aTrc
, JSObject
* aObj
)
2607 xpc::TraceXPCGlobal(aTrc
, aObj
);
2610 static bool sRegisteredDOMNames
= false;
2615 if (sRegisteredDOMNames
) {
2619 nsresult rv
= nsDOMClassInfo::Init();
2620 if (NS_FAILED(rv
)) {
2621 NS_ERROR("Could not initialize nsDOMClassInfo");
2625 // Register new DOM bindings
2626 nsScriptNameSpaceManager
* nameSpaceManager
= GetNameSpaceManager();
2627 if (!nameSpaceManager
) {
2628 NS_ERROR("Could not initialize nsScriptNameSpaceManager");
2629 return NS_ERROR_FAILURE
;
2631 mozilla::dom::Register(nameSpaceManager
);
2633 sRegisteredDOMNames
= true;
2640 CreateGlobalOptions
<nsGlobalWindow
>::PostCreateGlobal(JSContext
* aCx
,
2641 JS::Handle
<JSObject
*> aGlobal
)
2643 nsresult rv
= RegisterDOMNames();
2644 if (NS_FAILED(rv
)) {
2645 return Throw(aCx
, rv
);
2648 // Invoking the XPCWrappedNativeScope constructor automatically hooks it
2649 // up to the compartment of aGlobal.
2650 (void) new XPCWrappedNativeScope(aCx
, aGlobal
);
2656 AssertReturnTypeMatchesJitinfo(const JSJitInfo
* aJitInfo
,
2657 JS::Handle
<JS::Value
> aValue
)
2659 switch (aJitInfo
->returnType()) {
2660 case JSVAL_TYPE_UNKNOWN
:
2661 // Any value is good.
2663 case JSVAL_TYPE_DOUBLE
:
2664 // The value could actually be an int32 value as well.
2665 MOZ_ASSERT(aValue
.isNumber());
2667 case JSVAL_TYPE_INT32
:
2668 MOZ_ASSERT(aValue
.isInt32());
2670 case JSVAL_TYPE_UNDEFINED
:
2671 MOZ_ASSERT(aValue
.isUndefined());
2673 case JSVAL_TYPE_BOOLEAN
:
2674 MOZ_ASSERT(aValue
.isBoolean());
2676 case JSVAL_TYPE_STRING
:
2677 MOZ_ASSERT(aValue
.isString());
2679 case JSVAL_TYPE_NULL
:
2680 MOZ_ASSERT(aValue
.isNull());
2682 case JSVAL_TYPE_OBJECT
:
2683 MOZ_ASSERT(aValue
.isObject());
2686 // Someone messed up their jitinfo type.
2687 MOZ_ASSERT(false, "Unexpected JSValueType stored in jitinfo");
2694 CallerSubsumes(JSObject
*aObject
)
2696 nsIPrincipal
* objPrin
= nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject
));
2697 return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin
);
2701 } // namespace mozilla