Bumping manifests a=b2g-bump
[gecko.git] / js / xpconnect / src / XPCWrappedNativeJSOps.cpp
blob70bc4b67bc5d5668a3a93cf2d465217e10236ebc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
9 #include "xpcprivate.h"
10 #include "jsprf.h"
11 #include "mozilla/dom/BindingUtils.h"
12 #include "mozilla/Preferences.h"
13 #include "nsIAddonInterposition.h"
14 #include "AddonWrapper.h"
16 using namespace mozilla;
17 using namespace JS;
19 /***************************************************************************/
21 // All of the exceptions thrown into JS from this file go through here.
22 // That makes this a nice place to set a breakpoint.
24 static bool Throw(nsresult errNum, JSContext* cx)
26 XPCThrower::Throw(errNum, cx);
27 return false;
30 // Handy macro used in many callback stub below.
32 #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper) \
33 PR_BEGIN_MACRO \
34 if (!wrapper) \
35 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \
36 if (!wrapper->IsValid()) \
37 return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); \
38 PR_END_MACRO
40 /***************************************************************************/
42 static bool
43 ToStringGuts(XPCCallContext& ccx)
45 char* sz;
46 XPCWrappedNative* wrapper = ccx.GetWrapper();
48 if (wrapper)
49 sz = wrapper->ToString(ccx.GetTearOff());
50 else
51 sz = JS_smprintf("[xpconnect wrapped native prototype]");
53 if (!sz) {
54 JS_ReportOutOfMemory(ccx);
55 return false;
58 JSString* str = JS_NewStringCopyZ(ccx, sz);
59 JS_smprintf_free(sz);
60 if (!str)
61 return false;
63 ccx.SetRetVal(STRING_TO_JSVAL(str));
64 return true;
67 /***************************************************************************/
69 static bool
70 XPC_WN_Shared_ToString(JSContext* cx, unsigned argc, jsval* vp)
72 CallArgs args = CallArgsFromVp(argc, vp);
73 RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
74 if (!obj)
75 return false;
77 XPCCallContext ccx(JS_CALLER, cx, obj);
78 if (!ccx.IsValid())
79 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
80 ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
81 ccx.SetArgsAndResultPtr(args.length(), args.array(), vp);
82 return ToStringGuts(ccx);
85 static bool
86 XPC_WN_Shared_ToSource(JSContext* cx, unsigned argc, jsval* vp)
88 CallArgs args = CallArgsFromVp(argc, vp);
89 static const char empty[] = "({})";
90 JSString* str = JS_NewStringCopyN(cx, empty, sizeof(empty)-1);
91 if (!str)
92 return false;
93 args.rval().setString(str);
95 return true;
98 /***************************************************************************/
100 // A "double wrapped object" is a user JSObject that has been wrapped as a
101 // wrappedJS in order to be used by native code and then re-wrapped by a
102 // wrappedNative wrapper to be used by JS code. One might think of it as:
103 // wrappedNative(wrappedJS(underlying_JSObject))
104 // This is done (as opposed to just unwrapping the wrapped JS and automatically
105 // returning the underlying JSObject) so that JS callers will see what looks
106 // Like any other xpcom object - and be limited to use its interfaces.
108 // See the comment preceding nsIXPCWrappedJSObjectGetter in nsIXPConnect.idl.
110 static JSObject*
111 GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper)
113 RootedObject obj(ccx);
114 nsCOMPtr<nsIXPConnectWrappedJS>
115 underware = do_QueryInterface(wrapper->GetIdentityObject());
116 if (underware) {
117 RootedObject mainObj(ccx, underware->GetJSObject());
118 if (mainObj) {
119 RootedId id(ccx, ccx.GetRuntime()->
120 GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT));
122 JSAutoCompartment ac(ccx, mainObj);
124 RootedValue val(ccx);
125 if (JS_GetPropertyById(ccx, mainObj, id, &val) &&
126 !val.isPrimitive()) {
127 obj = val.toObjectOrNull();
131 return obj;
134 // This is the getter native function we use to handle 'wrappedJSObject' for
135 // double wrapped JSObjects.
137 static bool
138 XPC_WN_DoubleWrappedGetter(JSContext* cx, unsigned argc, jsval* vp)
140 CallArgs args = CallArgsFromVp(argc, vp);
142 RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
143 if (!obj)
144 return false;
146 XPCCallContext ccx(JS_CALLER, cx, obj);
147 XPCWrappedNative* wrapper = ccx.GetWrapper();
148 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
150 MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
152 RootedObject realObject(cx, GetDoubleWrappedJSObject(ccx, wrapper));
153 if (!realObject) {
154 // This is pretty unexpected at this point. The object originally
155 // responded to this get property call and now gives no object.
156 // XXX Should this throw something at the caller?
157 args.rval().setNull();
158 return true;
161 // It is a double wrapped object. This should really never appear in
162 // content these days, but addons still do it - see bug 965921.
163 if (MOZ_UNLIKELY(!nsContentUtils::IsCallerChrome())) {
164 JS_ReportError(cx, "Attempt to use .wrappedJSObject in untrusted code");
165 return false;
167 args.rval().setObject(*realObject);
168 return JS_WrapValue(cx, args.rval());
171 /***************************************************************************/
173 // This is our shared function to define properties on our JSObjects.
176 * NOTE:
177 * We *never* set the tearoff names (e.g. nsIFoo) as JS_ENUMERATE.
178 * We *never* set toString or toSource as JS_ENUMERATE.
181 static bool
182 DefinePropertyIfFound(XPCCallContext& ccx,
183 HandleObject obj,
184 HandleId idArg,
185 XPCNativeSet* set,
186 XPCNativeInterface* iface,
187 XPCNativeMember* member,
188 XPCWrappedNativeScope* scope,
189 bool reflectToStringAndToSource,
190 XPCWrappedNative* wrapperToReflectInterfaceNames,
191 XPCWrappedNative* wrapperToReflectDoubleWrap,
192 XPCNativeScriptableInfo* scriptableInfo,
193 unsigned propFlags,
194 bool* resolved)
196 RootedId id(ccx, idArg);
197 XPCJSRuntime* rt = ccx.GetRuntime();
198 bool found;
199 const char* name;
201 if (set) {
202 if (iface)
203 found = true;
204 else
205 found = set->FindMember(id, &member, &iface);
206 } else
207 found = (nullptr != (member = iface->FindMember(id)));
209 if (!found) {
210 if (reflectToStringAndToSource) {
211 JSNative call;
212 uint32_t flags = 0;
214 if (scriptableInfo) {
215 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(
216 scriptableInfo->GetCallback());
218 if (classInfo) {
219 nsresult rv = classInfo->GetFlags(&flags);
220 if (NS_FAILED(rv))
221 return Throw(rv, ccx);
225 bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT)
226 || Preferences::GetBool("dom.XPCToStringForDOMClasses", false);
228 if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING)
229 && overwriteToString)
231 call = XPC_WN_Shared_ToString;
232 name = rt->GetStringName(XPCJSRuntime::IDX_TO_STRING);
233 id = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING);
234 } else if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE)) {
235 call = XPC_WN_Shared_ToSource;
236 name = rt->GetStringName(XPCJSRuntime::IDX_TO_SOURCE);
237 id = rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE);
240 else
241 call = nullptr;
243 if (call) {
244 RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, obj, name));
245 if (!fun) {
246 JS_ReportOutOfMemory(ccx);
247 return false;
250 AutoResolveName arn(ccx, id);
251 if (resolved)
252 *resolved = true;
253 RootedObject value(ccx, JS_GetFunctionObject(fun));
254 return JS_DefinePropertyById(ccx, obj, id, value,
255 propFlags & ~JSPROP_ENUMERATE);
258 // This *might* be a tearoff name that is not yet part of our
259 // set. Let's lookup the name and see if it is the name of an
260 // interface. Then we'll see if the object actually *does* this
261 // interface and add a tearoff as necessary.
263 if (wrapperToReflectInterfaceNames) {
264 JSAutoByteString name;
265 AutoMarkingNativeInterfacePtr iface2(ccx);
266 XPCWrappedNativeTearOff* to;
267 RootedObject jso(ccx);
268 nsresult rv = NS_OK;
270 if (JSID_IS_STRING(id) &&
271 name.encodeLatin1(ccx, JSID_TO_STRING(id)) &&
272 (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr()), iface2) &&
273 nullptr != (to = wrapperToReflectInterfaceNames->
274 FindTearOff(iface2, true, &rv)) &&
275 nullptr != (jso = to->GetJSObject()))
278 AutoResolveName arn(ccx, id);
279 if (resolved)
280 *resolved = true;
281 return JS_DefinePropertyById(ccx, obj, id, jso,
282 propFlags & ~JSPROP_ENUMERATE);
283 } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) {
284 return Throw(rv, ccx);
288 // This *might* be a double wrapped JSObject
289 if (wrapperToReflectDoubleWrap &&
290 id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) &&
291 GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) {
292 // We build and add a getter function.
293 // A security check is done on a per-get basis.
295 JSFunction* fun;
297 id = rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
298 name = rt->GetStringName(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
300 fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter,
301 0, 0, obj, name);
303 if (!fun)
304 return false;
306 RootedObject funobj(ccx, JS_GetFunctionObject(fun));
307 if (!funobj)
308 return false;
310 propFlags |= JSPROP_GETTER | JSPROP_SHARED;
311 propFlags &= ~JSPROP_ENUMERATE;
313 AutoResolveName arn(ccx, id);
314 if (resolved)
315 *resolved = true;
316 return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags,
317 JS_DATA_TO_FUNC_PTR(JSPropertyOp, funobj.get()),
318 nullptr);
321 if (resolved)
322 *resolved = false;
323 return true;
326 if (!member) {
327 if (wrapperToReflectInterfaceNames) {
328 XPCWrappedNativeTearOff* to =
329 wrapperToReflectInterfaceNames->FindTearOff(iface, true);
331 if (!to)
332 return false;
333 RootedObject jso(ccx, to->GetJSObject());
334 if (!jso)
335 return false;
337 AutoResolveName arn(ccx, id);
338 if (resolved)
339 *resolved = true;
340 return JS_DefinePropertyById(ccx, obj, id, jso,
341 propFlags & ~JSPROP_ENUMERATE);
343 if (resolved)
344 *resolved = false;
345 return true;
348 if (member->IsConstant()) {
349 RootedValue val(ccx);
350 AutoResolveName arn(ccx, id);
351 if (resolved)
352 *resolved = true;
353 return member->GetConstantValue(ccx, iface, val.address()) &&
354 JS_DefinePropertyById(ccx, obj, id, val, propFlags);
357 if (scope->HasInterposition()) {
358 Rooted<JSPropertyDescriptor> desc(ccx);
359 if (!xpc::Interpose(ccx, obj, iface->GetIID(), id, &desc))
360 return false;
362 if (desc.object()) {
363 AutoResolveName arn(ccx, id);
364 if (resolved)
365 *resolved = true;
366 return JS_DefinePropertyById(ccx, obj, id, desc.value(), desc.attributes(),
367 desc.getter(), desc.setter());
371 if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) ||
372 id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE) ||
373 (scriptableInfo &&
374 scriptableInfo->GetFlags().DontEnumQueryInterface() &&
375 id == rt->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE)))
376 propFlags &= ~JSPROP_ENUMERATE;
378 RootedValue funval(ccx);
379 if (!member->NewFunctionObject(ccx, iface, obj, funval.address()))
380 return false;
382 if (member->IsMethod()) {
383 AutoResolveName arn(ccx, id);
384 if (resolved)
385 *resolved = true;
386 return JS_DefinePropertyById(ccx, obj, id, funval, propFlags);
389 // else...
391 MOZ_ASSERT(member->IsAttribute(), "way broken!");
393 propFlags |= JSPROP_GETTER | JSPROP_SHARED;
394 JSObject* funobj = funval.toObjectOrNull();
395 JSPropertyOp getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, funobj);
396 JSStrictPropertyOp setter;
397 if (member->IsWritableAttribute()) {
398 propFlags |= JSPROP_SETTER;
399 propFlags &= ~JSPROP_READONLY;
400 setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, funobj);
401 } else {
402 setter = js_GetterOnlyPropertyStub;
405 AutoResolveName arn(ccx, id);
406 if (resolved)
407 *resolved = true;
409 return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, getter, setter);
412 /***************************************************************************/
413 /***************************************************************************/
415 static bool
416 XPC_WN_OnlyIWrite_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
418 XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id);
419 XPCWrappedNative* wrapper = ccx.GetWrapper();
420 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
422 // Allow only XPConnect to add/set the property
423 if (ccx.GetResolveName() == id)
424 return true;
426 return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
429 static bool
430 XPC_WN_OnlyIWrite_SetPropertyStub(JSContext* cx, HandleObject obj, HandleId id, bool strict,
431 MutableHandleValue vp)
433 return XPC_WN_OnlyIWrite_AddPropertyStub(cx, obj, id, vp);
436 static bool
437 XPC_WN_CannotModifyPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
438 MutableHandleValue vp)
440 return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
443 static bool
444 XPC_WN_CantDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
445 bool* succeeded)
447 return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
450 static bool
451 XPC_WN_CannotModifyStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id, bool strict,
452 MutableHandleValue vp)
454 return XPC_WN_CannotModifyPropertyStub(cx, obj, id, vp);
457 static bool
458 XPC_WN_Shared_Convert(JSContext* cx, HandleObject obj, JSType type, MutableHandleValue vp)
460 if (type == JSTYPE_OBJECT) {
461 vp.set(OBJECT_TO_JSVAL(obj));
462 return true;
465 XPCCallContext ccx(JS_CALLER, cx, obj);
466 XPCWrappedNative* wrapper = ccx.GetWrapper();
467 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
469 switch (type) {
470 case JSTYPE_FUNCTION:
472 if (!ccx.GetTearOff()) {
473 XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
474 if (si && (si->GetFlags().WantCall() ||
475 si->GetFlags().WantConstruct())) {
476 vp.set(OBJECT_TO_JSVAL(obj));
477 return true;
481 return Throw(NS_ERROR_XPC_CANT_CONVERT_WN_TO_FUN, cx);
482 case JSTYPE_NUMBER:
483 vp.set(JS_GetNaNValue(cx));
484 return true;
485 case JSTYPE_BOOLEAN:
486 vp.set(JSVAL_TRUE);
487 return true;
488 case JSTYPE_VOID:
489 case JSTYPE_STRING:
491 ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING));
492 ccx.SetArgsAndResultPtr(0, nullptr, vp.address());
494 XPCNativeMember* member = ccx.GetMember();
495 if (member && member->IsMethod()) {
496 if (!XPCWrappedNative::CallMethod(ccx))
497 return false;
499 if (vp.isPrimitive())
500 return true;
503 // else...
504 return ToStringGuts(ccx);
506 default:
507 NS_ERROR("bad type in conversion");
508 return false;
510 NS_NOTREACHED("huh?");
511 return false;
514 static bool
515 XPC_WN_Shared_Enumerate(JSContext* cx, HandleObject obj)
517 XPCCallContext ccx(JS_CALLER, cx, obj);
518 XPCWrappedNative* wrapper = ccx.GetWrapper();
519 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
521 // Since we aren't going to enumerate tearoff names and the prototype
522 // handles non-mutated members, we can do this potential short-circuit.
523 if (!wrapper->HasMutatedSet())
524 return true;
526 XPCNativeSet* set = wrapper->GetSet();
527 XPCNativeSet* protoSet = wrapper->HasProto() ?
528 wrapper->GetProto()->GetSet() : nullptr;
530 uint16_t interface_count = set->GetInterfaceCount();
531 XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
532 for (uint16_t i = 0; i < interface_count; i++) {
533 XPCNativeInterface* iface = interfaceArray[i];
534 uint16_t member_count = iface->GetMemberCount();
535 for (uint16_t k = 0; k < member_count; k++) {
536 XPCNativeMember* member = iface->GetMemberAt(k);
537 jsid name = member->GetName();
539 // Skip if this member is going to come from the proto.
540 uint16_t index;
541 if (protoSet &&
542 protoSet->FindMember(name, nullptr, &index) && index == i)
543 continue;
544 if (!xpc_ForcePropertyResolve(cx, obj, name))
545 return false;
548 return true;
551 /***************************************************************************/
553 enum WNHelperType {
554 WN_NOHELPER,
555 WN_HELPER
558 static void
559 WrappedNativeFinalize(js::FreeOp* fop, JSObject* obj, WNHelperType helperType)
561 const js::Class* clazz = js::GetObjectClass(obj);
562 if (clazz->flags & JSCLASS_DOM_GLOBAL) {
563 mozilla::dom::DestroyProtoAndIfaceCache(obj);
565 nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
566 if (!p)
567 return;
569 XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
570 if (helperType == WN_HELPER)
571 wrapper->GetScriptableCallback()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj);
572 wrapper->FlatJSObjectFinalized();
575 static void
576 XPC_WN_NoHelper_Finalize(js::FreeOp* fop, JSObject* obj)
578 WrappedNativeFinalize(fop, obj, WN_NOHELPER);
582 * General comment about XPConnect tracing: Given a C++ object |wrapper| and its
583 * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS
584 * engine to mark |obj|. Eventually, this will lead to the trace hook being
585 * called for |obj|. The trace hook should call |wrapper->TraceInside|, which
586 * should mark any JS objects held by |wrapper| as members.
589 static void
590 MarkWrappedNative(JSTracer* trc, JSObject* obj)
592 const js::Class* clazz = js::GetObjectClass(obj);
593 if (clazz->flags & JSCLASS_DOM_GLOBAL) {
594 mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
596 MOZ_ASSERT(IS_WN_CLASS(clazz));
598 XPCWrappedNative* wrapper = XPCWrappedNative::Get(obj);
599 if (wrapper && wrapper->IsValid())
600 wrapper->TraceInside(trc);
603 /* static */ void
604 XPCWrappedNative::Trace(JSTracer* trc, JSObject* obj)
606 MarkWrappedNative(trc, obj);
609 static bool
610 XPC_WN_NoHelper_Resolve(JSContext* cx, HandleObject obj, HandleId id)
612 XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id);
613 XPCWrappedNative* wrapper = ccx.GetWrapper();
614 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
616 XPCNativeSet* set = ccx.GetSet();
617 if (!set)
618 return true;
620 // Don't resolve properties that are on our prototype.
621 if (ccx.GetInterface() && !ccx.GetStaticMemberIsLocal())
622 return true;
624 return DefinePropertyIfFound(ccx, obj, id,
625 set, nullptr, nullptr, wrapper->GetScope(),
626 true, wrapper, wrapper, nullptr,
627 JSPROP_ENUMERATE |
628 JSPROP_READONLY |
629 JSPROP_PERMANENT, nullptr);
632 static JSObject*
633 XPC_WN_OuterObject(JSContext* cx, HandleObject objArg)
635 JSObject* obj = objArg;
637 XPCWrappedNative* wrapper = XPCWrappedNative::Get(obj);
638 if (!wrapper) {
639 Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
641 return nullptr;
644 if (!wrapper->IsValid()) {
645 Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);
647 return nullptr;
650 XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
651 if (si && si->GetFlags().WantOuterObject()) {
652 RootedObject newThis(cx);
653 nsresult rv =
654 si->GetCallback()->OuterObject(wrapper, cx, obj, newThis.address());
656 if (NS_FAILED(rv)) {
657 Throw(rv, cx);
659 return nullptr;
662 obj = newThis;
665 return obj;
668 const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = {
669 { // base
670 "XPCWrappedNative_NoHelper", // name;
671 WRAPPER_SLOTS |
672 JSCLASS_PRIVATE_IS_NSISUPPORTS, // flags
674 /* Mandatory non-null function pointer members. */
675 XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty
676 XPC_WN_CantDeletePropertyStub, // delProperty
677 JS_PropertyStub, // getProperty
678 XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty
680 XPC_WN_Shared_Enumerate, // enumerate
681 XPC_WN_NoHelper_Resolve, // resolve
682 XPC_WN_Shared_Convert, // convert
683 XPC_WN_NoHelper_Finalize, // finalize
685 /* Optionally non-null members start here. */
686 nullptr, // call
687 nullptr, // construct
688 nullptr, // hasInstance
689 XPCWrappedNative::Trace, // trace
690 JS_NULL_CLASS_SPEC,
692 // ClassExtension
694 nullptr, // outerObject
695 nullptr, // innerObject
696 nullptr, // iteratorObject
697 true, // isWrappedNative
700 // ObjectOps
702 nullptr, // lookupGeneric
703 nullptr, // lookupProperty
704 nullptr, // lookupElement
705 nullptr, // defineGeneric
706 nullptr, // defineProperty
707 nullptr, // defineElement
708 nullptr, // getGeneric
709 nullptr, // getProperty
710 nullptr, // getElement
711 nullptr, // setGeneric
712 nullptr, // setProperty
713 nullptr, // setElement
714 nullptr, // getGenericAttributes
715 nullptr, // setGenericAttributes
716 nullptr, // deleteGeneric
717 nullptr, nullptr, // watch/unwatch
718 nullptr, // slice
719 XPC_WN_JSOp_Enumerate,
720 XPC_WN_JSOp_ThisObject,
723 0 // interfacesBitmap
727 /***************************************************************************/
729 static bool
730 XPC_WN_MaybeResolvingPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
732 XPCCallContext ccx(JS_CALLER, cx, obj);
733 XPCWrappedNative* wrapper = ccx.GetWrapper();
734 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
736 if (ccx.GetResolvingWrapper() == wrapper)
737 return true;
738 return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
741 static bool
742 XPC_WN_MaybeResolvingStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id, bool strict,
743 MutableHandleValue vp)
745 return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp);
748 static bool
749 XPC_WN_MaybeResolvingDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id, bool* succeeded)
751 XPCCallContext ccx(JS_CALLER, cx, obj);
752 XPCWrappedNative* wrapper = ccx.GetWrapper();
753 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
755 if (ccx.GetResolvingWrapper() == wrapper) {
756 *succeeded = true;
757 return true;
759 return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
762 // macro fun!
763 #define PRE_HELPER_STUB \
764 JSObject* unwrapped = js::CheckedUnwrap(obj, false); \
765 if (!unwrapped) { \
766 JS_ReportError(cx, "Permission denied to operate on object."); \
767 return false; \
769 if (!IS_WN_REFLECTOR(unwrapped)) { \
770 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \
772 XPCWrappedNative* wrapper = XPCWrappedNative::Get(unwrapped); \
773 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \
774 bool retval = true; \
775 nsresult rv = wrapper->GetScriptableCallback()->
777 #define POST_HELPER_STUB \
778 if (NS_FAILED(rv)) \
779 return Throw(rv, cx); \
780 return retval;
782 static bool
783 XPC_WN_Helper_AddProperty(JSContext* cx, HandleObject obj, HandleId id,
784 MutableHandleValue vp)
786 PRE_HELPER_STUB
787 AddProperty(wrapper, cx, obj, id, vp.address(), &retval);
788 POST_HELPER_STUB
791 static bool
792 XPC_WN_Helper_DelProperty(JSContext* cx, HandleObject obj, HandleId id,
793 bool* succeeded)
795 *succeeded = true;
796 PRE_HELPER_STUB
797 DelProperty(wrapper, cx, obj, id, &retval);
798 POST_HELPER_STUB
801 bool
802 XPC_WN_Helper_GetProperty(JSContext* cx, HandleObject obj, HandleId id,
803 MutableHandleValue vp)
805 PRE_HELPER_STUB
806 GetProperty(wrapper, cx, obj, id, vp.address(), &retval);
807 POST_HELPER_STUB
810 bool
811 XPC_WN_Helper_SetProperty(JSContext* cx, HandleObject obj, HandleId id, bool strict,
812 MutableHandleValue vp)
814 PRE_HELPER_STUB
815 SetProperty(wrapper, cx, obj, id, vp.address(), &retval);
816 POST_HELPER_STUB
819 static bool
820 XPC_WN_Helper_Convert(JSContext* cx, HandleObject obj, JSType type, MutableHandleValue vp)
822 PRE_HELPER_STUB
823 Convert(wrapper, cx, obj, type, vp.address(), &retval);
824 POST_HELPER_STUB
827 static bool
828 XPC_WN_Helper_Call(JSContext* cx, unsigned argc, jsval* vp)
830 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
831 // N.B. we want obj to be the callee, not JS_THIS(cx, vp)
832 RootedObject obj(cx, &args.callee());
834 XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE, args.length(),
835 args.array(), args.rval().address());
836 if (!ccx.IsValid())
837 return false;
839 PRE_HELPER_STUB
840 Call(wrapper, cx, obj, args, &retval);
841 POST_HELPER_STUB
844 static bool
845 XPC_WN_Helper_Construct(JSContext* cx, unsigned argc, jsval* vp)
847 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
848 RootedObject obj(cx, &args.callee());
849 if (!obj)
850 return false;
852 XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE, args.length(),
853 args.array(), args.rval().address());
854 if (!ccx.IsValid())
855 return false;
857 PRE_HELPER_STUB
858 Construct(wrapper, cx, obj, args, &retval);
859 POST_HELPER_STUB
862 static bool
863 XPC_WN_Helper_HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue valp, bool* bp)
865 bool retval2;
866 PRE_HELPER_STUB
867 HasInstance(wrapper, cx, obj, valp, &retval2, &retval);
868 *bp = retval2;
869 POST_HELPER_STUB
872 static void
873 XPC_WN_Helper_Finalize(js::FreeOp* fop, JSObject* obj)
875 WrappedNativeFinalize(fop, obj, WN_HELPER);
878 static bool
879 XPC_WN_Helper_NewResolve(JSContext* cx, HandleObject obj, HandleId id,
880 MutableHandleObject objp)
882 nsresult rv = NS_OK;
883 bool retval = true;
884 RootedObject obj2FromScriptable(cx);
885 XPCCallContext ccx(JS_CALLER, cx, obj);
886 XPCWrappedNative* wrapper = ccx.GetWrapper();
887 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
889 RootedId old(cx, ccx.SetResolveName(id));
891 XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
892 if (si && si->GetFlags().WantNewResolve()) {
893 XPCWrappedNative* oldResolvingWrapper;
894 bool allowPropMods = si->GetFlags().AllowPropModsDuringResolve();
896 if (allowPropMods)
897 oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper);
899 rv = si->GetCallback()->NewResolve(wrapper, cx, obj, id,
900 obj2FromScriptable.address(), &retval);
902 if (allowPropMods)
903 (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
906 old = ccx.SetResolveName(old);
907 MOZ_ASSERT(old == id, "bad nest");
909 if (NS_FAILED(rv)) {
910 return Throw(rv, cx);
913 if (obj2FromScriptable) {
914 objp.set(obj2FromScriptable);
915 } else if (wrapper->HasMutatedSet()) {
916 // We are here if scriptable did not resolve this property and
917 // it *might* be in the instance set but not the proto set.
919 XPCNativeSet* set = wrapper->GetSet();
920 XPCNativeSet* protoSet = wrapper->HasProto() ?
921 wrapper->GetProto()->GetSet() : nullptr;
922 XPCNativeMember* member;
923 XPCNativeInterface* iface;
924 bool IsLocal;
926 if (set->FindMember(id, &member, &iface, protoSet, &IsLocal) &&
927 IsLocal) {
928 XPCWrappedNative* oldResolvingWrapper;
930 XPCNativeScriptableFlags siFlags(0);
931 if (si)
932 siFlags = si->GetFlags();
934 unsigned enumFlag =
935 siFlags.DontEnumStaticProps() ? 0 : JSPROP_ENUMERATE;
937 XPCWrappedNative* wrapperForInterfaceNames =
938 siFlags.DontReflectInterfaceNames() ? nullptr : wrapper;
940 bool resolved;
941 oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper);
942 retval = DefinePropertyIfFound(ccx, obj, id,
943 set, iface, member,
944 wrapper->GetScope(),
945 false,
946 wrapperForInterfaceNames,
947 nullptr, si,
948 enumFlag, &resolved);
949 (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
950 if (retval && resolved)
951 objp.set(obj);
955 return retval;
958 /***************************************************************************/
961 Here are the enumerator cases:
963 set jsclass enumerate to stub (unless noted otherwise)
965 if ( helper wants new enumerate )
966 if ( DONT_ENUM_STATICS )
967 forward to scriptable enumerate
968 else
969 if ( set not mutated )
970 forward to scriptable enumerate
971 else
972 call shared enumerate
973 forward to scriptable enumerate
974 else if ( helper wants old enumerate )
975 use this JSOp
976 if ( DONT_ENUM_STATICS )
977 call scriptable enumerate
978 call stub
979 else
980 if ( set not mutated )
981 call scriptable enumerate
982 call stub
983 else
984 call shared enumerate
985 call scriptable enumerate
986 call stub
988 else //... if ( helper wants NO enumerate )
989 if ( DONT_ENUM_STATICS )
990 use enumerate stub - don't use this JSOp thing at all
991 else
992 do shared enumerate - don't use this JSOp thing at all
995 bool
996 XPC_WN_JSOp_Enumerate(JSContext* cx, HandleObject obj, JSIterateOp enum_op,
997 MutableHandleValue statep, MutableHandleId idp)
999 const js::Class* clazz = js::GetObjectClass(obj);
1000 if (!IS_WN_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) {
1001 // obj must be a prototype object or a wrapper w/o a
1002 // helper. Short circuit this call to the default
1003 // implementation.
1005 return JS_EnumerateState(cx, obj, enum_op, statep, idp);
1008 XPCCallContext ccx(JS_CALLER, cx, obj);
1009 XPCWrappedNative* wrapper = ccx.GetWrapper();
1010 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1012 XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
1013 if (!si)
1014 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1016 bool retval = true;
1017 nsresult rv;
1019 if (si->GetFlags().WantNewEnumerate()) {
1020 if (((enum_op == JSENUMERATE_INIT &&
1021 !si->GetFlags().DontEnumStaticProps()) ||
1022 enum_op == JSENUMERATE_INIT_ALL) &&
1023 wrapper->HasMutatedSet() &&
1024 !XPC_WN_Shared_Enumerate(cx, obj)) {
1025 statep.set(JSVAL_NULL);
1026 return false;
1029 // XXX Might we really need to wrap this call and *also* call
1030 // js_ObjectOps.enumerate ???
1032 rv = si->GetCallback()->
1033 NewEnumerate(wrapper, cx, obj, enum_op, statep.address(), idp.address(), &retval);
1035 if ((enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) &&
1036 (NS_FAILED(rv) || !retval)) {
1037 statep.set(JSVAL_NULL);
1040 if (NS_FAILED(rv))
1041 return Throw(rv, cx);
1042 return retval;
1045 if (si->GetFlags().WantEnumerate()) {
1046 if (enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) {
1047 if ((enum_op == JSENUMERATE_INIT_ALL ||
1048 !si->GetFlags().DontEnumStaticProps()) &&
1049 wrapper->HasMutatedSet() &&
1050 !XPC_WN_Shared_Enumerate(cx, obj)) {
1051 statep.set(JSVAL_NULL);
1052 return false;
1054 rv = si->GetCallback()->
1055 Enumerate(wrapper, cx, obj, &retval);
1057 if (NS_FAILED(rv) || !retval)
1058 statep.set(JSVAL_NULL);
1060 if (NS_FAILED(rv))
1061 return Throw(rv, cx);
1062 if (!retval)
1063 return false;
1064 // Then fall through and call the default implementation...
1068 // else call js_ObjectOps.enumerate...
1070 return JS_EnumerateState(cx, obj, enum_op, statep, idp);
1073 JSObject*
1074 XPC_WN_JSOp_ThisObject(JSContext* cx, HandleObject obj)
1076 return JS_ObjectToOuterObject(cx, obj);
1079 /***************************************************************************/
1081 // static
1082 XPCNativeScriptableInfo*
1083 XPCNativeScriptableInfo::Construct(const XPCNativeScriptableCreateInfo* sci)
1085 MOZ_ASSERT(sci, "bad param");
1086 MOZ_ASSERT(sci->GetCallback(), "bad param");
1088 XPCNativeScriptableInfo* newObj =
1089 new XPCNativeScriptableInfo(sci->GetCallback());
1090 if (!newObj)
1091 return nullptr;
1093 char* name = nullptr;
1094 if (NS_FAILED(sci->GetCallback()->GetClassName(&name)) || !name) {
1095 delete newObj;
1096 return nullptr;
1099 bool success;
1101 XPCJSRuntime* rt = XPCJSRuntime::Get();
1102 XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap();
1103 success = map->GetNewOrUsed(sci->GetFlags(), name,
1104 sci->GetInterfacesBitmap(), newObj);
1106 if (!success) {
1107 delete newObj;
1108 return nullptr;
1111 return newObj;
1114 void
1115 XPCNativeScriptableShared::PopulateJSClass()
1117 MOZ_ASSERT(mJSClass.base.name, "bad state!");
1119 mJSClass.base.flags = WRAPPER_SLOTS |
1120 JSCLASS_PRIVATE_IS_NSISUPPORTS |
1121 JSCLASS_NEW_RESOLVE;
1123 if (mFlags.IsGlobalObject())
1124 mJSClass.base.flags |= XPCONNECT_GLOBAL_FLAGS;
1126 JSPropertyOp addProperty;
1127 if (mFlags.WantAddProperty())
1128 addProperty = XPC_WN_Helper_AddProperty;
1129 else if (mFlags.UseJSStubForAddProperty())
1130 addProperty = JS_PropertyStub;
1131 else if (mFlags.AllowPropModsDuringResolve())
1132 addProperty = XPC_WN_MaybeResolvingPropertyStub;
1133 else
1134 addProperty = XPC_WN_CannotModifyPropertyStub;
1135 mJSClass.base.addProperty = addProperty;
1137 JSDeletePropertyOp delProperty;
1138 if (mFlags.WantDelProperty())
1139 delProperty = XPC_WN_Helper_DelProperty;
1140 else if (mFlags.UseJSStubForDelProperty())
1141 delProperty = JS_DeletePropertyStub;
1142 else if (mFlags.AllowPropModsDuringResolve())
1143 delProperty = XPC_WN_MaybeResolvingDeletePropertyStub;
1144 else
1145 delProperty = XPC_WN_CantDeletePropertyStub;
1146 mJSClass.base.delProperty = delProperty;
1148 if (mFlags.WantGetProperty())
1149 mJSClass.base.getProperty = XPC_WN_Helper_GetProperty;
1150 else
1151 mJSClass.base.getProperty = JS_PropertyStub;
1153 JSStrictPropertyOp setProperty;
1154 if (mFlags.WantSetProperty())
1155 setProperty = XPC_WN_Helper_SetProperty;
1156 else if (mFlags.UseJSStubForSetProperty())
1157 setProperty = JS_StrictPropertyStub;
1158 else if (mFlags.AllowPropModsDuringResolve())
1159 setProperty = XPC_WN_MaybeResolvingStrictPropertyStub;
1160 else
1161 setProperty = XPC_WN_CannotModifyStrictPropertyStub;
1162 mJSClass.base.setProperty = setProperty;
1164 // We figure out most of the enumerate strategy at call time.
1166 if (mFlags.WantNewEnumerate() || mFlags.WantEnumerate() ||
1167 mFlags.DontEnumStaticProps())
1168 mJSClass.base.enumerate = JS_EnumerateStub;
1169 else
1170 mJSClass.base.enumerate = XPC_WN_Shared_Enumerate;
1172 // We have to figure out resolve strategy at call time
1173 mJSClass.base.resolve = (JSResolveOp) XPC_WN_Helper_NewResolve;
1175 // We need to respect content-defined toString() hooks on Window objects.
1176 // In particular, js::DefaultValue checks for a convert stub, and the one
1177 // we would install below ignores anything implemented in JS.
1179 // We've always had this behavior for most XPCWrappedNative-implemented
1180 // objects. However, Window was special, because the outer-window proxy
1181 // had a null convert hook, which means that we'd end up with the default
1182 // JS-engine behavior (which respects toString() overrides). We've fixed
1183 // the convert hook on the outer-window proxy to invoke the defaultValue
1184 // hook on the proxy, which in this case invokes js::DefaultValue on the
1185 // target. So now we need to special-case this for Window to maintain
1186 // consistent behavior. This can go away once Window is on WebIDL bindings.
1188 // Note that WantOuterObject() is true if and only if this is a Window object.
1189 if (mFlags.WantConvert())
1190 mJSClass.base.convert = XPC_WN_Helper_Convert;
1191 else if (mFlags.WantOuterObject())
1192 mJSClass.base.convert = JS_ConvertStub;
1193 else
1194 mJSClass.base.convert = XPC_WN_Shared_Convert;
1196 if (mFlags.WantFinalize())
1197 mJSClass.base.finalize = XPC_WN_Helper_Finalize;
1198 else
1199 mJSClass.base.finalize = XPC_WN_NoHelper_Finalize;
1201 js::ObjectOps* ops = &mJSClass.base.ops;
1202 ops->enumerate = XPC_WN_JSOp_Enumerate;
1203 ops->thisObject = XPC_WN_JSOp_ThisObject;
1206 if (mFlags.WantCall())
1207 mJSClass.base.call = XPC_WN_Helper_Call;
1208 if (mFlags.WantConstruct())
1209 mJSClass.base.construct = XPC_WN_Helper_Construct;
1211 if (mFlags.WantHasInstance())
1212 mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance;
1214 if (mFlags.IsGlobalObject())
1215 mJSClass.base.trace = JS_GlobalObjectTraceHook;
1216 else
1217 mJSClass.base.trace = XPCWrappedNative::Trace;
1219 if (mFlags.WantOuterObject())
1220 mJSClass.base.ext.outerObject = XPC_WN_OuterObject;
1222 mJSClass.base.ext.isWrappedNative = true;
1225 /***************************************************************************/
1226 /***************************************************************************/
1228 // Compatibility hack.
1230 // XPConnect used to do all sorts of funny tricks to find the "correct"
1231 // |this| object for a given method (often to the detriment of proper
1232 // call/apply). When these tricks were removed, a fair amount of chrome
1233 // code broke, because it was relying on being able to grab methods off
1234 // some XPCOM object (like the nsITelemetry service) and invoke them without
1235 // a proper |this|. So, if it's quite clear that we're in this situation and
1236 // about to use a |this| argument that just won't work, fix things up.
1238 // This hack is only useful for getters/setters if someone sets an XPCOM object
1239 // as the prototype for a vanilla JS object and expects the XPCOM attributes to
1240 // work on the derived object, which we really don't want to support. But we
1241 // handle it anyway, for now, to minimize regression risk on an already-risky
1242 // landing.
1244 // This hack is mainly useful for the NoHelper JSClass. We also fix up
1245 // Components.utils because it implements nsIXPCScriptable (giving it a custom
1246 // JSClass) but not nsIClassInfo (which would put the methods on a prototype).
1248 #define IS_NOHELPER_CLASS(clasp) (clasp == &XPC_WN_NoHelper_JSClass.base)
1249 #define IS_CU_CLASS(clasp) (clasp->name[0] == 'n' && !strcmp(clasp->name, "nsXPCComponents_Utils"))
1251 MOZ_ALWAYS_INLINE JSObject*
1252 FixUpThisIfBroken(JSObject* obj, JSObject* funobj)
1254 if (funobj) {
1255 const js::Class* parentClass = js::GetObjectClass(js::GetObjectParent(funobj));
1256 if (MOZ_UNLIKELY((IS_NOHELPER_CLASS(parentClass) || IS_CU_CLASS(parentClass)) &&
1257 (js::GetObjectClass(obj) != parentClass)))
1259 return js::GetObjectParent(funobj);
1262 return obj;
1265 bool
1266 XPC_WN_CallMethod(JSContext* cx, unsigned argc, jsval* vp)
1268 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
1269 MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
1270 RootedObject funobj(cx, &args.callee());
1272 RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
1273 if (!obj)
1274 return false;
1276 obj = FixUpThisIfBroken(obj, funobj);
1277 XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
1278 args.array(), vp);
1279 XPCWrappedNative* wrapper = ccx.GetWrapper();
1280 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1282 XPCNativeInterface* iface;
1283 XPCNativeMember* member;
1285 if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
1286 return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
1287 ccx.SetCallInfo(iface, member, false);
1288 return XPCWrappedNative::CallMethod(ccx);
1291 bool
1292 XPC_WN_GetterSetter(JSContext* cx, unsigned argc, jsval* vp)
1294 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
1295 MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
1296 RootedObject funobj(cx, &args.callee());
1298 RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
1299 if (!obj)
1300 return false;
1302 obj = FixUpThisIfBroken(obj, funobj);
1303 XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
1304 args.array(), vp);
1305 XPCWrappedNative* wrapper = ccx.GetWrapper();
1306 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1308 XPCNativeInterface* iface;
1309 XPCNativeMember* member;
1311 if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
1312 return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
1314 if (args.length() != 0 && member->IsWritableAttribute()) {
1315 ccx.SetCallInfo(iface, member, true);
1316 bool retval = XPCWrappedNative::SetAttribute(ccx);
1317 if (retval)
1318 args.rval().set(args[0]);
1319 return retval;
1321 // else...
1323 ccx.SetCallInfo(iface, member, false);
1324 return XPCWrappedNative::GetAttribute(ccx);
1327 /***************************************************************************/
1329 static bool
1330 XPC_WN_Shared_Proto_Enumerate(JSContext* cx, HandleObject obj)
1332 MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
1333 js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass ||
1334 js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
1335 js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass,
1336 "bad proto");
1337 XPCWrappedNativeProto* self =
1338 (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1339 if (!self)
1340 return false;
1342 if (self->GetScriptableInfo() &&
1343 self->GetScriptableInfo()->GetFlags().DontEnumStaticProps())
1344 return true;
1346 XPCNativeSet* set = self->GetSet();
1347 if (!set)
1348 return false;
1350 XPCCallContext ccx(JS_CALLER, cx);
1351 if (!ccx.IsValid())
1352 return false;
1354 uint16_t interface_count = set->GetInterfaceCount();
1355 XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
1356 for (uint16_t i = 0; i < interface_count; i++) {
1357 XPCNativeInterface* iface = interfaceArray[i];
1358 uint16_t member_count = iface->GetMemberCount();
1360 for (uint16_t k = 0; k < member_count; k++) {
1361 if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
1362 return false;
1366 return true;
1369 static void
1370 XPC_WN_Shared_Proto_Finalize(js::FreeOp* fop, JSObject* obj)
1372 // This can be null if xpc shutdown has already happened
1373 XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1374 if (p)
1375 p->JSProtoObjectFinalized(fop, obj);
1378 static void
1379 XPC_WN_Shared_Proto_Trace(JSTracer* trc, JSObject* obj)
1381 // This can be null if xpc shutdown has already happened
1382 XPCWrappedNativeProto* p =
1383 (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1384 if (p)
1385 p->TraceInside(trc);
1388 /*****************************************************/
1390 static bool
1391 XPC_WN_ModsAllowed_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id)
1393 MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
1394 js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
1395 "bad proto");
1397 XPCWrappedNativeProto* self =
1398 (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1399 if (!self)
1400 return false;
1402 XPCCallContext ccx(JS_CALLER, cx);
1403 if (!ccx.IsValid())
1404 return false;
1406 XPCNativeScriptableInfo* si = self->GetScriptableInfo();
1407 unsigned enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ?
1408 0 : JSPROP_ENUMERATE;
1410 return DefinePropertyIfFound(ccx, obj, id,
1411 self->GetSet(), nullptr, nullptr,
1412 self->GetScope(),
1413 true, nullptr, nullptr, si,
1414 enumFlag, nullptr);
1417 const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
1418 "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name;
1419 WRAPPER_SLOTS, // flags;
1421 /* Mandatory non-null function pointer members. */
1422 JS_PropertyStub, // addProperty;
1423 JS_DeletePropertyStub, // delProperty;
1424 JS_PropertyStub, // getProperty;
1425 JS_StrictPropertyStub, // setProperty;
1426 XPC_WN_Shared_Proto_Enumerate, // enumerate;
1427 XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
1428 JS_ConvertStub, // convert;
1429 XPC_WN_Shared_Proto_Finalize, // finalize;
1431 /* Optionally non-null members start here. */
1432 nullptr, // call;
1433 nullptr, // construct;
1434 nullptr, // hasInstance;
1435 XPC_WN_Shared_Proto_Trace, // trace;
1437 JS_NULL_CLASS_SPEC,
1438 JS_NULL_CLASS_EXT,
1439 XPC_WN_WithCall_ObjectOps
1442 const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
1443 "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name;
1444 WRAPPER_SLOTS, // flags;
1446 /* Mandatory non-null function pointer members. */
1447 JS_PropertyStub, // addProperty;
1448 JS_DeletePropertyStub, // delProperty;
1449 JS_PropertyStub, // getProperty;
1450 JS_StrictPropertyStub, // setProperty;
1451 XPC_WN_Shared_Proto_Enumerate, // enumerate;
1452 XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
1453 JS_ConvertStub, // convert;
1454 XPC_WN_Shared_Proto_Finalize, // finalize;
1456 /* Optionally non-null members start here. */
1457 nullptr, // call;
1458 nullptr, // construct;
1459 nullptr, // hasInstance;
1460 XPC_WN_Shared_Proto_Trace, // trace;
1462 JS_NULL_CLASS_SPEC,
1463 JS_NULL_CLASS_EXT,
1464 XPC_WN_NoCall_ObjectOps
1467 /***************************************************************************/
1469 static bool
1470 XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
1471 MutableHandleValue vp)
1473 MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
1474 js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass,
1475 "bad proto");
1477 XPCWrappedNativeProto* self =
1478 (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1479 if (!self)
1480 return false;
1482 XPCCallContext ccx(JS_CALLER, cx);
1483 if (!ccx.IsValid())
1484 return false;
1486 // Allow XPConnect to add the property only
1487 if (ccx.GetResolveName() == id)
1488 return true;
1490 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1493 static bool
1494 XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext* cx, HandleObject obj, HandleId id, bool strict,
1495 MutableHandleValue vp)
1497 return XPC_WN_OnlyIWrite_Proto_AddPropertyStub(cx, obj, id, vp);
1500 static bool
1501 XPC_WN_NoMods_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id)
1503 MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
1504 js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass,
1505 "bad proto");
1507 XPCWrappedNativeProto* self =
1508 (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1509 if (!self)
1510 return false;
1512 XPCCallContext ccx(JS_CALLER, cx);
1513 if (!ccx.IsValid())
1514 return false;
1516 XPCNativeScriptableInfo* si = self->GetScriptableInfo();
1517 unsigned enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ?
1518 0 : JSPROP_ENUMERATE;
1520 return DefinePropertyIfFound(ccx, obj, id,
1521 self->GetSet(), nullptr, nullptr,
1522 self->GetScope(),
1523 true, nullptr, nullptr, si,
1524 JSPROP_READONLY |
1525 JSPROP_PERMANENT |
1526 enumFlag, nullptr);
1529 const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = {
1530 "XPC_WN_NoMods_WithCall_Proto_JSClass", // name;
1531 WRAPPER_SLOTS, // flags;
1533 /* Mandatory non-null function pointer members. */
1534 XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty;
1535 XPC_WN_CantDeletePropertyStub, // delProperty;
1536 JS_PropertyStub, // getProperty;
1537 XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty;
1538 XPC_WN_Shared_Proto_Enumerate, // enumerate;
1539 XPC_WN_NoMods_Proto_Resolve, // resolve;
1540 JS_ConvertStub, // convert;
1541 XPC_WN_Shared_Proto_Finalize, // finalize;
1543 /* Optionally non-null members start here. */
1544 nullptr, // call;
1545 nullptr, // construct;
1546 nullptr, // hasInstance;
1547 XPC_WN_Shared_Proto_Trace, // trace;
1549 JS_NULL_CLASS_SPEC,
1550 JS_NULL_CLASS_EXT,
1551 XPC_WN_WithCall_ObjectOps
1554 const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = {
1555 "XPC_WN_NoMods_NoCall_Proto_JSClass", // name;
1556 WRAPPER_SLOTS, // flags;
1558 /* Mandatory non-null function pointer members. */
1559 XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty;
1560 XPC_WN_CantDeletePropertyStub, // delProperty;
1561 JS_PropertyStub, // getProperty;
1562 XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty;
1563 XPC_WN_Shared_Proto_Enumerate, // enumerate;
1564 XPC_WN_NoMods_Proto_Resolve, // resolve;
1565 JS_ConvertStub, // convert;
1566 XPC_WN_Shared_Proto_Finalize, // finalize;
1568 /* Optionally non-null members start here. */
1569 nullptr, // call;
1570 nullptr, // construct;
1571 nullptr, // hasInstance;
1572 XPC_WN_Shared_Proto_Trace, // trace;
1574 JS_NULL_CLASS_SPEC,
1575 JS_NULL_CLASS_EXT,
1576 XPC_WN_NoCall_ObjectOps
1579 /***************************************************************************/
1581 static bool
1582 XPC_WN_TearOff_Enumerate(JSContext* cx, HandleObject obj)
1584 XPCCallContext ccx(JS_CALLER, cx, obj);
1585 XPCWrappedNative* wrapper = ccx.GetWrapper();
1586 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1588 XPCWrappedNativeTearOff* to = ccx.GetTearOff();
1589 XPCNativeInterface* iface;
1591 if (!to || nullptr == (iface = to->GetInterface()))
1592 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1594 uint16_t member_count = iface->GetMemberCount();
1595 for (uint16_t k = 0; k < member_count; k++) {
1596 if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
1597 return false;
1600 return true;
1603 static bool
1604 XPC_WN_TearOff_Resolve(JSContext* cx, HandleObject obj, HandleId id)
1606 XPCCallContext ccx(JS_CALLER, cx, obj);
1607 XPCWrappedNative* wrapper = ccx.GetWrapper();
1608 THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1610 XPCWrappedNativeTearOff* to = ccx.GetTearOff();
1611 XPCNativeInterface* iface;
1613 if (!to || nullptr == (iface = to->GetInterface()))
1614 return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1616 return DefinePropertyIfFound(ccx, obj, id, nullptr, iface, nullptr,
1617 wrapper->GetScope(),
1618 true, nullptr, nullptr, nullptr,
1619 JSPROP_READONLY |
1620 JSPROP_PERMANENT |
1621 JSPROP_ENUMERATE, nullptr);
1624 static void
1625 XPC_WN_TearOff_Finalize(js::FreeOp* fop, JSObject* obj)
1627 XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
1628 xpc_GetJSPrivate(obj);
1629 if (!p)
1630 return;
1631 p->JSObjectFinalized();
1634 const js::Class XPC_WN_Tearoff_JSClass = {
1635 "WrappedNative_TearOff", // name;
1636 WRAPPER_SLOTS, // flags;
1638 XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty;
1639 XPC_WN_CantDeletePropertyStub, // delProperty;
1640 JS_PropertyStub, // getProperty;
1641 XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty;
1642 XPC_WN_TearOff_Enumerate, // enumerate;
1643 XPC_WN_TearOff_Resolve, // resolve;
1644 XPC_WN_Shared_Convert, // convert;
1645 XPC_WN_TearOff_Finalize // finalize;