Back to index

lightning-sunbird  0.9+nobinonly
xpcwrappednativejsops.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=80:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1999
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *   John Bandhauer <jband@netscape.com> (original author)
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
00043 
00044 #include "xpcprivate.h"
00045 #include "XPCNativeWrapper.h"
00046 
00047 /***************************************************************************/
00048 
00049 // All of the exceptions thrown into JS from this file go through here.
00050 // That makes this a nice place to set a breakpoint.
00051 
00052 static JSBool Throw(uintN errNum, JSContext* cx)
00053 {
00054     XPCThrower::Throw(errNum, cx);
00055     return JS_FALSE;
00056 }
00057 
00058 // Handy macro used in many callback stub below.
00059 
00060 #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper)                         \
00061     PR_BEGIN_MACRO                                                           \
00062     if(!wrapper)                                                             \
00063         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);                   \
00064     if(!wrapper->IsValid())                                                  \
00065         return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);                    \
00066     PR_END_MACRO
00067 
00068 // We rely on the engine only giving us jsval ids that are actually the
00069 // self-same jsvals that are in the atom table (that is, if the id represents
00070 // a string). So, we assert by converting the jsval to an id and then back
00071 // to a jsval and comparing pointers. If the engine ever breaks this promise
00072 // then we will scream.
00073 #ifdef DEBUG
00074 #define CHECK_IDVAL(cx, idval)                                               \
00075     PR_BEGIN_MACRO                                                           \
00076     if(JSVAL_IS_STRING(idval))                                               \
00077     {                                                                        \
00078         jsid d_id;                                                           \
00079         jsval d_val;                                                         \
00080         NS_ASSERTION(JS_ValueToId(cx, idval, &d_id), "JS_ValueToId failed!");\
00081         NS_ASSERTION(JS_IdToValue(cx, d_id, &d_val), "JS_IdToValue failed!");\
00082         NS_ASSERTION(d_val == idval, "id differs from id in atom table!");   \
00083     }                                                                        \
00084     PR_END_MACRO
00085 #else
00086 #define CHECK_IDVAL(cx, idval) ((void)0)
00087 #endif
00088 
00089 /***************************************************************************/
00090 
00091 static JSBool
00092 ToStringGuts(XPCCallContext& ccx)
00093 {
00094     char* sz;
00095     XPCWrappedNative* wrapper = ccx.GetWrapper();
00096 
00097     if(wrapper)
00098         sz = wrapper->ToString(ccx, ccx.GetTearOff());
00099     else
00100         sz = JS_smprintf("[xpconnect wrapped native prototype]");
00101 
00102     if(!sz)
00103     {
00104         JS_ReportOutOfMemory(ccx);
00105         return JS_FALSE;
00106     }
00107 
00108     JSString* str = JS_NewString(ccx, sz, strlen(sz));
00109     if(!str)
00110     {
00111         JS_smprintf_free(sz);
00112         // JS_ReportOutOfMemory already reported by failed JS_NewString
00113         return JS_FALSE;
00114     }
00115 
00116     ccx.SetRetVal(STRING_TO_JSVAL(str));
00117     return JS_TRUE;
00118 }
00119 
00120 /***************************************************************************/
00121 
00122 JS_STATIC_DLL_CALLBACK(JSBool)
00123 XPC_WN_Shared_ToString(JSContext *cx, JSObject *obj,
00124                        uintN argc, jsval *argv, jsval *vp)
00125 {
00126     XPCCallContext ccx(JS_CALLER, cx, obj);
00127     ccx.SetName(ccx.GetRuntime()->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING));
00128     ccx.SetArgsAndResultPtr(argc, argv, vp);
00129     return ToStringGuts(ccx);
00130 }
00131 
00132 JS_STATIC_DLL_CALLBACK(JSBool)
00133 XPC_WN_Shared_ToSource(JSContext *cx, JSObject *obj,
00134                        uintN argc, jsval *argv, jsval *vp)
00135 {
00136     static const char empty[] = "{}";
00137     *vp = STRING_TO_JSVAL(JS_NewStringCopyN(cx, empty, sizeof(empty)-1));
00138     return JS_TRUE;
00139 }
00140 
00141 /***************************************************************************/
00142 
00143 // A "double wrapped object" is a user JSObject that has been wrapped as a
00144 // wrappedJS in order to be used by native code and then re-wrapped by a
00145 // wrappedNative wrapper to be used by JS code. One might think of it as:
00146 //    wrappedNative(wrappedJS(underlying_JSObject))
00147 // This is done (as opposed to just unwrapping the wrapped JS and automatically
00148 // returning the underlying JSObject) so that JS callers will see what looks
00149 // Like any other xpcom object - and be limited to use its interfaces.
00150 //
00151 // See the comment preceeding nsIXPCWrappedJSObjectGetter in nsIXPConnect.idl.
00152 
00153 static JSObject*
00154 GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper)
00155 {
00156     JSObject* obj = nsnull;
00157     nsCOMPtr<nsIXPConnectWrappedJS>
00158         underware = do_QueryInterface(wrapper->GetIdentityObject());
00159     if(underware)
00160     {
00161         JSObject* mainObj = nsnull;
00162         if(NS_SUCCEEDED(underware->GetJSObject(&mainObj)) && mainObj)
00163         {
00164             jsid id = ccx.GetRuntime()->
00165                     GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
00166 
00167             jsval val;
00168             if(OBJ_GET_PROPERTY(ccx, mainObj, id,
00169                                 &val) && !JSVAL_IS_PRIMITIVE(val))
00170             {
00171                 obj = JSVAL_TO_OBJECT(val);
00172             }
00173         }
00174     }
00175     return obj;
00176 }
00177 
00178 // This is the getter native function we use to handle 'wrappedJSObject' for
00179 // double wrapped JSObjects.
00180 
00181 JS_STATIC_DLL_CALLBACK(JSBool)
00182 XPC_WN_DoubleWrappedGetter(JSContext *cx, JSObject *obj,
00183                            uintN argc, jsval *argv, jsval *vp)
00184 {
00185     XPCCallContext ccx(JS_CALLER, cx, obj);
00186     XPCWrappedNative* wrapper = ccx.GetWrapper();
00187     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00188 
00189     NS_ASSERTION(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION, "bad function");
00190 
00191     JSObject* realObject = GetDoubleWrappedJSObject(ccx, wrapper);
00192     if(!realObject)
00193     {
00194         // This is pretty unexpected at this point. The object originally
00195         // responded to this get property call and now gives no object.
00196         // XXX Should this throw something at the caller?
00197         *vp = JSVAL_NULL;
00198         return JS_TRUE;
00199     }
00200 
00201     // It is a double wrapped object. Figure out if the caller
00202     // is allowed to see it.
00203 
00204     nsIXPCSecurityManager* sm;
00205     XPCContext* xpcc = ccx.GetXPCContext();
00206 
00207     sm = xpcc->GetAppropriateSecurityManager(
00208                     nsIXPCSecurityManager::HOOK_GET_PROPERTY);
00209     if(sm)
00210     {
00211         AutoMarkingNativeInterfacePtr iface(ccx);
00212         iface = XPCNativeInterface::
00213                     GetNewOrUsed(ccx, &NS_GET_IID(nsIXPCWrappedJSObjectGetter));
00214 
00215         if(iface)
00216         {
00217             jsval idval = ccx.GetRuntime()->
00218                         GetStringJSVal(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
00219 
00220             ccx.SetCallInfo(iface, iface->GetMemberAt(1), JS_FALSE);
00221             if(NS_FAILED(sm->
00222                     CanAccess(nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
00223                               &ccx, ccx,
00224                               ccx.GetFlattenedJSObject(),
00225                               wrapper->GetIdentityObject(),
00226                               wrapper->GetClassInfo(), idval,
00227                               wrapper->GetSecurityInfoAddr())))
00228             {
00229                 // The SecurityManager should have set an exception.
00230                 return JS_FALSE;
00231             }
00232         }
00233     }
00234     *vp = OBJECT_TO_JSVAL(realObject);
00235     return JS_TRUE;
00236 }
00237 
00238 /***************************************************************************/
00239 
00240 // This is our shared function to define properties on our JSObjects.
00241 
00242 /*
00243  * NOTE:
00244  * We *never* set the tearoff names (e.g. nsIFoo) as JS_ENUMERATE.
00245  * We *never* set toString or toSource as JS_ENUMERATE.
00246  */
00247 
00248 static JSBool
00249 DefinePropertyIfFound(XPCCallContext& ccx,
00250                       JSObject *obj, jsval idval,
00251                       XPCNativeSet* set,
00252                       XPCNativeInterface* iface,
00253                       XPCNativeMember* member,
00254                       XPCWrappedNativeScope* scope,
00255                       JSBool reflectToStringAndToSource,
00256                       XPCWrappedNative* wrapperToReflectInterfaceNames,
00257                       XPCWrappedNative* wrapperToReflectDoubleWrap,
00258                       XPCNativeScriptableInfo* scriptableInfo,
00259                       uintN propFlags,
00260                       JSBool* resolved)
00261 {
00262     XPCJSRuntime* rt = ccx.GetRuntime();
00263     JSBool found;
00264     const char* name;
00265     jsid id;
00266 
00267     if(set)
00268     {
00269         if(iface)
00270             found = JS_TRUE;
00271         else
00272             found = set->FindMember(idval, &member, &iface);
00273     }
00274     else
00275         found = (nsnull != (member = iface->FindMember(idval)));
00276 
00277     if(!found)
00278     {
00279         HANDLE_POSSIBLE_NAME_CASE_ERROR(ccx, set, iface, idval);
00280 
00281         if(reflectToStringAndToSource)
00282         {
00283             JSNative call;
00284 
00285             if(idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING))
00286             {
00287                 call = XPC_WN_Shared_ToString;
00288                 name = rt->GetStringName(XPCJSRuntime::IDX_TO_STRING);
00289                 id   = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING);
00290             }
00291             else if(idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_SOURCE))
00292             {
00293                 call = XPC_WN_Shared_ToSource;
00294                 name = rt->GetStringName(XPCJSRuntime::IDX_TO_SOURCE);
00295                 id   = rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE);
00296             }
00297 
00298             else
00299                 call = nsnull;
00300 
00301             if(call)
00302             {
00303                 JSFunction* fun = JS_NewFunction(ccx, call, 0, 0, obj, name);
00304                 if(!fun)
00305                 {
00306                     JS_ReportOutOfMemory(ccx);
00307                     return JS_FALSE;
00308                 }
00309 
00310                 AutoResolveName arn(ccx, idval);
00311                 if(resolved)
00312                     *resolved = JS_TRUE;
00313                 return OBJ_DEFINE_PROPERTY(ccx, obj, id,
00314                                            OBJECT_TO_JSVAL(JS_GetFunctionObject(fun)),
00315                                            nsnull, nsnull,
00316                                            propFlags & ~JSPROP_ENUMERATE,
00317                                            nsnull);
00318             }
00319         }
00320         // This *might* be a tearoff name that is not yet part of our
00321         // set. Let's lookup the name and see if it is the name of an
00322         // interface. Then we'll see if the object actually *does* this
00323         // interface and add a tearoff as necessary.
00324 
00325         if(wrapperToReflectInterfaceNames)
00326         {
00327             AutoMarkingNativeInterfacePtr iface2(ccx);
00328             XPCWrappedNativeTearOff* to;
00329             JSObject* jso;
00330 
00331             if(JSVAL_IS_STRING(idval) &&
00332                nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) &&
00333                (iface2 = XPCNativeInterface::GetNewOrUsed(ccx, name), iface2) &&
00334                nsnull != (to = wrapperToReflectInterfaceNames->
00335                                     FindTearOff(ccx, iface2, JS_TRUE)) &&
00336                nsnull != (jso = to->GetJSObject()))
00337 
00338             {
00339                 AutoResolveName arn(ccx, idval);
00340                 if(resolved)
00341                     *resolved = JS_TRUE;
00342                 return JS_ValueToId(ccx, idval, &id) &&
00343                        OBJ_DEFINE_PROPERTY(ccx, obj, id, OBJECT_TO_JSVAL(jso),
00344                                            nsnull, nsnull,
00345                                            propFlags & ~JSPROP_ENUMERATE,
00346                                            nsnull);
00347             }
00348         }
00349 
00350         // This *might* be a double wrapped JSObject
00351         if(wrapperToReflectDoubleWrap &&
00352            idval == rt->GetStringJSVal(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) &&
00353            GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap))
00354         {
00355             // We build and add a getter function.
00356             // A security check is done on a per-get basis.
00357 
00358             JSFunction* fun;
00359 
00360             id = rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
00361             name = rt->GetStringName(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
00362 
00363             fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter,
00364                                  0, JSFUN_GETTER, obj, name);
00365 
00366             if(!fun)
00367                 return JS_FALSE;
00368 
00369             JSObject* funobj = JS_GetFunctionObject(fun);
00370             if(!funobj)
00371                 return JS_FALSE;
00372 
00373             propFlags |= JSPROP_GETTER;
00374             propFlags &= ~JSPROP_ENUMERATE;
00375 
00376             AutoResolveName arn(ccx, idval);
00377             if(resolved)
00378                 *resolved = JS_TRUE;
00379             return OBJ_DEFINE_PROPERTY(ccx, obj, id, JSVAL_VOID,
00380                                        (JSPropertyOp) funobj, nsnull,
00381                                        propFlags, nsnull);
00382         }
00383 
00384 #ifdef XPC_IDISPATCH_SUPPORT
00385         // Check to see if there's an IDispatch tearoff     
00386         if(wrapperToReflectInterfaceNames &&
00387             XPCIDispatchExtension::DefineProperty(ccx, obj, 
00388                 idval, wrapperToReflectInterfaceNames, propFlags, resolved))
00389             return JS_TRUE;
00390 #endif
00391         
00392         if(resolved)
00393             *resolved = JS_FALSE;
00394         return JS_TRUE;
00395     }
00396 
00397     if(!member)
00398     {
00399         if(wrapperToReflectInterfaceNames)
00400         {
00401             XPCWrappedNativeTearOff* to =
00402               wrapperToReflectInterfaceNames->FindTearOff(ccx, iface, JS_TRUE);
00403 
00404             if(!to)
00405                 return JS_FALSE;
00406             JSObject* jso = to->GetJSObject();
00407             if(!jso)
00408                 return JS_FALSE;
00409 
00410             AutoResolveName arn(ccx, idval);
00411             if(resolved)
00412                 *resolved = JS_TRUE;
00413             return JS_ValueToId(ccx, idval, &id) &&
00414                    OBJ_DEFINE_PROPERTY(ccx, obj, id, OBJECT_TO_JSVAL(jso),
00415                                        nsnull, nsnull,
00416                                        propFlags & ~JSPROP_ENUMERATE,
00417                                        nsnull);
00418         }
00419         if(resolved)
00420             *resolved = JS_FALSE;
00421         return JS_TRUE;
00422     }
00423 
00424     if(member->IsConstant())
00425     {
00426         jsval val;
00427         AutoResolveName arn(ccx, idval);
00428         if(resolved)
00429             *resolved = JS_TRUE;
00430         return member->GetValue(ccx, iface, &val) &&
00431                JS_ValueToId(ccx, idval, &id) &&
00432                OBJ_DEFINE_PROPERTY(ccx, obj, id, val, nsnull, nsnull,
00433                                    propFlags, nsnull);
00434     }
00435 
00436     if(idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING) ||
00437        idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_SOURCE) ||
00438        (scriptableInfo &&
00439         scriptableInfo->GetFlags().DontEnumQueryInterface() &&
00440         idval == rt->GetStringJSVal(XPCJSRuntime::IDX_QUERY_INTERFACE)))
00441         propFlags &= ~JSPROP_ENUMERATE;
00442 
00443     JSObject* funobj;
00444     
00445     {
00446         // scoped gc protection of funval
00447         jsval funval;
00448 
00449         if(!member->GetValue(ccx, iface, &funval))
00450             return JS_FALSE;
00451     
00452         AUTO_MARK_JSVAL(ccx, funval);
00453 
00454         funobj = xpc_CloneJSFunction(ccx, JSVAL_TO_OBJECT(funval), obj);
00455         if(!funobj)
00456             return JS_FALSE;
00457     }
00458 
00459     // protect funobj until it is actually attached
00460     AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(funobj));
00461 
00462 #ifdef off_DEBUG_jband
00463     {
00464         static int cloneCount = 0;
00465         if(!(++cloneCount%10))
00466             printf("<><><> %d cloned functions created\n", cloneCount);
00467     }
00468 #endif
00469 
00470     if(member->IsMethod())
00471     {
00472         AutoResolveName arn(ccx, idval);
00473         if(resolved)
00474             *resolved = JS_TRUE;
00475         return JS_ValueToId(ccx, idval, &id) &&
00476                OBJ_DEFINE_PROPERTY(ccx, obj, id, OBJECT_TO_JSVAL(funobj),
00477                                    nsnull, nsnull, propFlags, nsnull);
00478     }
00479 
00480     // else...
00481 
00482     NS_ASSERTION(member->IsAttribute(), "way broken!");
00483 
00484     propFlags |= JSPROP_GETTER | JSPROP_SHARED;
00485     if(member->IsWritableAttribute())
00486     {
00487         propFlags |= JSPROP_SETTER;
00488         propFlags &= ~JSPROP_READONLY;
00489     }
00490 
00491     AutoResolveName arn(ccx, idval);
00492     if(resolved)
00493         *resolved = JS_TRUE;
00494     return JS_ValueToId(ccx, idval, &id) &&
00495            OBJ_DEFINE_PROPERTY(ccx, obj, id, JSVAL_VOID,
00496                                (JSPropertyOp) funobj,
00497                                (JSPropertyOp) funobj,
00498                                propFlags, nsnull);
00499 }
00500 
00501 /***************************************************************************/
00502 /***************************************************************************/
00503 
00504 JS_STATIC_DLL_CALLBACK(JSBool)
00505 XPC_WN_OnlyIWrite_PropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00506 {
00507     CHECK_IDVAL(cx, idval);
00508 
00509     XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, idval);
00510     XPCWrappedNative* wrapper = ccx.GetWrapper();
00511     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00512 
00513     // Allow only XPConnect to add the property
00514     if(ccx.GetResolveName() == idval)
00515         return JS_TRUE;
00516 
00517     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
00518 }
00519 
00520 JS_STATIC_DLL_CALLBACK(JSBool)
00521 XPC_WN_CannotModifyPropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00522 {
00523     CHECK_IDVAL(cx, idval);
00524     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
00525 }
00526 
00527 JS_STATIC_DLL_CALLBACK(JSBool)
00528 XPC_WN_Shared_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
00529 {
00530     if(type == JSTYPE_OBJECT)
00531     {
00532         *vp = OBJECT_TO_JSVAL(obj);
00533         return JS_TRUE;
00534     }
00535 
00536     XPCCallContext ccx(JS_CALLER, cx, obj);
00537     XPCWrappedNative* wrapper = ccx.GetWrapper();
00538     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00539 
00540     switch (type)
00541     {
00542         case JSTYPE_FUNCTION:
00543             {
00544                 if(!ccx.GetTearOff())
00545                 {
00546                     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
00547                     if(si && (si->GetFlags().WantCall() ||
00548                               si->GetFlags().WantConstruct()))
00549                     {
00550                         *vp = OBJECT_TO_JSVAL(obj);
00551                         return JS_TRUE;
00552                     }
00553                 }
00554             }
00555             return Throw(NS_ERROR_XPC_CANT_CONVERT_WN_TO_FUN, cx);
00556         case JSTYPE_NUMBER:
00557             *vp = JS_GetNaNValue(cx);
00558             return JS_TRUE;
00559         case JSTYPE_BOOLEAN:
00560             *vp = JSVAL_TRUE;
00561             return JS_TRUE;
00562         case JSTYPE_VOID:
00563         case JSTYPE_STRING:
00564         {
00565             ccx.SetName(ccx.GetRuntime()->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING));
00566             ccx.SetArgsAndResultPtr(0, nsnull, vp);
00567 
00568             XPCNativeMember* member = ccx.GetMember();
00569             if(member && member->IsMethod())
00570             {
00571                 if(!XPCWrappedNative::CallMethod(ccx))
00572                     return JS_FALSE;
00573 
00574                 if(JSVAL_IS_PRIMITIVE(*vp))
00575                     return JS_TRUE;
00576             }
00577 
00578             // else...
00579             return ToStringGuts(ccx);
00580         }
00581         default:
00582             NS_ERROR("bad type in conversion");
00583             return JS_FALSE;
00584     }
00585     NS_NOTREACHED("huh?");
00586     return JS_FALSE;
00587 }
00588 
00589 JS_STATIC_DLL_CALLBACK(JSBool)
00590 XPC_WN_Shared_Enumerate(JSContext *cx, JSObject *obj)
00591 {
00592     XPCCallContext ccx(JS_CALLER, cx, obj);
00593     XPCWrappedNative* wrapper = ccx.GetWrapper();
00594     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00595 
00596     // Since we aren't going to enumerate tearoff names and the prototype
00597     // handles non-mutated members, we can do this potential short-circuit.
00598     if(!wrapper->HasMutatedSet())
00599         return JS_TRUE;
00600 
00601     // Since we might be using this in the helper case, we check to
00602     // see if this is all avoidable.
00603 
00604     if(wrapper->GetScriptableInfo() &&
00605        wrapper->GetScriptableInfo()->GetFlags().DontEnumStaticProps())
00606         return JS_TRUE;
00607 
00608     XPCNativeSet* set = wrapper->GetSet();
00609     XPCNativeSet* protoSet = wrapper->HasProto() ?
00610                                 wrapper->GetProto()->GetSet() : nsnull;
00611 
00612     PRUint16 interface_count = set->GetInterfaceCount();
00613     XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
00614     for(PRUint16 i = 0; i < interface_count; i++)
00615     {
00616         XPCNativeInterface* iface = interfaceArray[i];
00617 #ifdef XPC_IDISPATCH_SUPPORT
00618         if(iface->GetIID()->Equals(NSID_IDISPATCH))
00619         {
00620             XPCIDispatchExtension::Enumerate(ccx, obj, wrapper);
00621             continue;
00622         }
00623 #endif
00624         PRUint16 member_count = iface->GetMemberCount();
00625         for(PRUint16 k = 0; k < member_count; k++)
00626         {
00627             XPCNativeMember* member = iface->GetMemberAt(k);
00628             jsval name = member->GetName();
00629 
00630             // Skip if this member is going to come from the proto.
00631             PRUint16 index;
00632             if(protoSet &&
00633                protoSet->FindMember(name, nsnull, &index) && index == i)
00634                 continue;
00635             if(!xpc_ForcePropertyResolve(cx, obj, name))
00636                 return JS_FALSE;
00637         }
00638     }
00639     return JS_TRUE;
00640 }
00641 
00642 /***************************************************************************/
00643 
00644 JS_STATIC_DLL_CALLBACK(void)
00645 XPC_WN_NoHelper_Finalize(JSContext *cx, JSObject *obj)
00646 {
00647     XPCWrappedNative* p = (XPCWrappedNative*) JS_GetPrivate(cx, obj);
00648     if(!p)
00649         return;
00650     p->FlatJSObjectFinalized(cx, obj);
00651 }
00652 
00653 static void
00654 MarkScopeJSObjects(JSContext *cx, XPCWrappedNativeScope* scope, void *arg)
00655 {
00656     NS_ASSERTION(scope, "bad scope");
00657 
00658     JSObject* obj;
00659 
00660     obj = scope->GetGlobalJSObject();
00661     NS_ASSERTION(scope, "bad scope JSObject");
00662     JS_MarkGCThing(cx, obj, "XPCWrappedNativeScope::mGlobalJSObject", arg);
00663 
00664     obj = scope->GetPrototypeJSObject();
00665     if(obj)
00666     {
00667         JS_MarkGCThing(cx, obj, "XPCWrappedNativeScope::mPrototypeJSObject", arg);
00668     }
00669 
00670     obj = scope->GetPrototypeJSFunction();
00671     if(obj)
00672     {
00673         JS_MarkGCThing(cx, obj, "XPCWrappedNativeScope::mPrototypeJSFunction", arg);
00674     }
00675 }
00676 
00677 void
00678 xpc_MarkForValidWrapper(JSContext *cx, XPCWrappedNative* wrapper, void *arg)
00679 {
00680     // NOTE: It might be nice to also do the wrapper->Mark() call here too.
00681     // That call marks the wrapper's and wrapper's proto's interface sets.
00682     // We currently do that in the GC callback code. The reason we don't do that
00683     // here is because the bits used in that marking do unpleasant things to the
00684     // member counts in the interface and interface set objects. Those counts
00685     // are used in the DealWithDyingGCThings calls that are part of this JS GC
00686     // marking phase. By doing these calls later during our GC callback we 
00687     // avoid that problem. Arguably this could be changed. But it ain't broke.
00688 
00689     // However, we do need to call the wrapper's MarkBeforeJSFinalize so that
00690     // it can be sure that its (potentially shared) JSClass gets marked. The
00691     // danger is that a live wrapper might not be in a wrapper map and thus
00692     // won't be fully marked in the GC callback. This can happen if there is
00693     // a security exception during wrapper creation or if during wrapper
00694     // creation it is determined that the wrapper is not needed. In those cases
00695     // the wrapper can never actually be used from JS code - so resources like
00696     // the interface set will never be accessed. But the JS engine will still
00697     // need to use the JSClass. So, some marking is required for protection.
00698 
00699     wrapper->MarkBeforeJSFinalize(cx);
00700      
00701     if(wrapper->HasProto())
00702     {
00703         JSObject* obj = wrapper->GetProto()->GetJSProtoObject();
00704         NS_ASSERTION(obj, "bad proto");
00705         JS_MarkGCThing(cx, obj, "XPCWrappedNativeProto::mJSProtoObject", arg);
00706     }
00707     MarkScopeJSObjects(cx, wrapper->GetScope(), arg);
00708 }
00709 
00710 JS_STATIC_DLL_CALLBACK(uint32)
00711 XPC_WN_Shared_Mark(JSContext *cx, JSObject *obj, void *arg)
00712 {
00713     XPCWrappedNative* wrapper =
00714         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
00715 
00716     if(wrapper && wrapper->IsValid())
00717         xpc_MarkForValidWrapper(cx, wrapper, arg);
00718     return 1;
00719 }
00720 
00721 JS_STATIC_DLL_CALLBACK(JSBool)
00722 XPC_WN_NoHelper_Resolve(JSContext *cx, JSObject *obj, jsval idval)
00723 {
00724     CHECK_IDVAL(cx, idval);
00725 
00726     XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, idval);
00727     XPCWrappedNative* wrapper = ccx.GetWrapper();
00728     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00729 
00730     XPCNativeSet* set = ccx.GetSet();
00731     if(!set)
00732         return JS_TRUE;
00733 
00734     // Don't resolve properties that are on our prototype.
00735     if(ccx.GetInterface() && !ccx.GetStaticMemberIsLocal())
00736         return JS_TRUE;
00737 
00738     return DefinePropertyIfFound(ccx, obj, idval,
00739                                  set, nsnull, nsnull, wrapper->GetScope(),
00740                                  JS_TRUE, wrapper, wrapper, nsnull,
00741                                  JSPROP_ENUMERATE |
00742                                  JSPROP_READONLY |
00743                                  JSPROP_PERMANENT, nsnull);
00744 }
00745 
00746 nsISupports *
00747 GetIdentityObject(JSContext *cx, JSObject *obj)
00748 {
00749     XPCWrappedNative *wrapper;
00750 
00751     if(XPCNativeWrapper::IsNativeWrapper(cx, obj))
00752         wrapper = XPCNativeWrapper::GetWrappedNative(cx, obj);
00753     else
00754         wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
00755 
00756     if(!wrapper) {
00757         return nsnull;
00758     }
00759 
00760     return wrapper->GetIdentityObject();
00761 }
00762 
00763 JS_STATIC_DLL_CALLBACK(JSBool)
00764 XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
00765 {
00766     *bp = JS_FALSE;
00767 
00768     XPCWrappedNative *wrapper =
00769         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
00770     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00771 
00772     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
00773     if(si && si->GetFlags().WantEquality())
00774     {
00775         nsresult rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp);
00776 
00777         if(NS_FAILED(rv))
00778             return Throw(rv, cx);
00779     }
00780     else if(!JSVAL_IS_PRIMITIVE(v))
00781     {
00782         JSObject *other = JSVAL_TO_OBJECT(v);
00783 
00784         *bp = (obj == other ||
00785                GetIdentityObject(cx, obj) == GetIdentityObject(cx, other));
00786     }
00787 
00788     return JS_TRUE;
00789 }
00790 
00791 JS_STATIC_DLL_CALLBACK(JSObject *)
00792 XPC_WN_OuterObject(JSContext *cx, JSObject *obj)
00793 {
00794     XPCWrappedNative *wrapper =
00795         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
00796     if(!wrapper)
00797     {
00798         Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
00799 
00800         return nsnull;
00801     }
00802 
00803     if(!wrapper->IsValid())
00804     {
00805         Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);
00806 
00807         return nsnull;
00808     }
00809 
00810     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
00811     if(si && si->GetFlags().WantOuterObject())
00812     {
00813         JSObject *newThis;
00814         nsresult rv =
00815             si->GetCallback()->OuterObject(wrapper, cx, obj, &newThis);
00816 
00817         if(NS_FAILED(rv))
00818         {
00819             Throw(rv, cx);
00820 
00821             return nsnull;
00822         }
00823 
00824         obj = newThis;
00825     }
00826 
00827     return obj;
00828 }
00829 
00830 JS_STATIC_DLL_CALLBACK(JSObject *)
00831 XPC_WN_InnerObject(JSContext *cx, JSObject *obj)
00832 {
00833     XPCWrappedNative *wrapper =
00834         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
00835     if(!wrapper)
00836     {
00837         Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
00838 
00839         return nsnull;
00840     }
00841 
00842     if(!wrapper->IsValid())
00843     {
00844         Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);
00845 
00846         return nsnull;
00847     }
00848 
00849     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
00850     if(si && si->GetFlags().WantInnerObject())
00851     {
00852         JSObject *newThis;
00853         nsresult rv =
00854             si->GetCallback()->InnerObject(wrapper, cx, obj, &newThis);
00855 
00856         if(NS_FAILED(rv))
00857         {
00858             Throw(rv, cx);
00859 
00860             return nsnull;
00861         }
00862 
00863         obj = newThis;
00864     }
00865 
00866     return obj;
00867 }
00868 
00869 JSExtendedClass XPC_WN_NoHelper_JSClass = {
00870     {
00871         "XPCWrappedNative_NoHelper",    // name;
00872         JSCLASS_HAS_PRIVATE |
00873         JSCLASS_PRIVATE_IS_NSISUPPORTS |
00874         JSCLASS_IS_EXTENDED, // flags;
00875 
00876         /* Mandatory non-null function pointer members. */
00877         XPC_WN_OnlyIWrite_PropertyStub, // addProperty;
00878         XPC_WN_CannotModifyPropertyStub,// delProperty;
00879         JS_PropertyStub,                // getProperty;
00880         XPC_WN_OnlyIWrite_PropertyStub, // setProperty;
00881 
00882         XPC_WN_Shared_Enumerate,        // enumerate;
00883         XPC_WN_NoHelper_Resolve,        // resolve;
00884         XPC_WN_Shared_Convert,          // convert;
00885         XPC_WN_NoHelper_Finalize,       // finalize;
00886 
00887         /* Optionally non-null members start here. */
00888         nsnull,                         // getObjectOps;
00889         nsnull,                         // checkAccess;
00890         nsnull,                         // call;
00891         nsnull,                         // construct;
00892         nsnull,                         // xdrObject;
00893         nsnull,                         // hasInstance;
00894         XPC_WN_Shared_Mark,             // mark;
00895         nsnull                          // spare;
00896     },
00897     XPC_WN_Equality,
00898     XPC_WN_OuterObject,
00899     XPC_WN_InnerObject,
00900     nsnull,nsnull,nsnull,nsnull,nsnull
00901 };
00902 
00903 
00904 /***************************************************************************/
00905 
00906 JS_STATIC_DLL_CALLBACK(JSBool)
00907 XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00908 {
00909     CHECK_IDVAL(cx, idval);
00910     XPCCallContext ccx(JS_CALLER, cx, obj);
00911     XPCWrappedNative* wrapper = ccx.GetWrapper();
00912     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
00913 
00914     if(ccx.GetResolvingWrapper() == wrapper)
00915         return JS_TRUE;
00916     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
00917 }
00918 
00919 // macro fun!
00920 #define PRE_HELPER_STUB                                                      \
00921     XPCWrappedNative* wrapper =                                              \
00922         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);               \
00923     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);                            \
00924     PRBool retval = JS_TRUE;                                                 \
00925     nsresult rv = wrapper->GetScriptableCallback()->
00926 
00927 #define POST_HELPER_STUB                                                     \
00928     if(NS_FAILED(rv))                                                        \
00929         return Throw(rv, cx);                                                \
00930     return retval;
00931 
00932 JS_STATIC_DLL_CALLBACK(JSBool)
00933 XPC_WN_Helper_AddProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00934 {
00935     PRE_HELPER_STUB
00936     AddProperty(wrapper, cx, obj, idval, vp, &retval);
00937     POST_HELPER_STUB
00938 }
00939 
00940 JS_STATIC_DLL_CALLBACK(JSBool)
00941 XPC_WN_Helper_DelProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00942 {
00943     PRE_HELPER_STUB
00944     DelProperty(wrapper, cx, obj, idval, vp, &retval);
00945     POST_HELPER_STUB
00946 }
00947 
00948 JS_STATIC_DLL_CALLBACK(JSBool)
00949 XPC_WN_Helper_GetProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00950 {
00951     PRE_HELPER_STUB
00952     GetProperty(wrapper, cx, obj, idval, vp, &retval);
00953     POST_HELPER_STUB
00954 }
00955 
00956 JS_STATIC_DLL_CALLBACK(JSBool)
00957 XPC_WN_Helper_SetProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
00958 {
00959     PRE_HELPER_STUB
00960     SetProperty(wrapper, cx, obj, idval, vp, &retval);
00961     POST_HELPER_STUB
00962 }
00963 
00964 JS_STATIC_DLL_CALLBACK(JSBool)
00965 XPC_WN_Helper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
00966 {
00967     PRE_HELPER_STUB
00968     Convert(wrapper, cx, obj, type, vp, &retval);
00969     POST_HELPER_STUB
00970 }
00971 
00972 JS_STATIC_DLL_CALLBACK(JSBool)
00973 XPC_WN_Helper_CheckAccess(JSContext *cx, JSObject *obj, jsval idval,
00974                           JSAccessMode mode, jsval *vp)
00975 {
00976     CHECK_IDVAL(cx, idval);
00977     PRE_HELPER_STUB
00978     CheckAccess(wrapper, cx, obj, idval, mode, vp, &retval);
00979     POST_HELPER_STUB
00980 }
00981 
00982 JS_STATIC_DLL_CALLBACK(JSBool)
00983 XPC_WN_Helper_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00984                    jsval *rval)
00985 {
00986     // this is a hack to get the obj of the actual object not the object
00987     // that JS thinks is the 'this' (which it passes as 'obj').
00988     if(!(obj = (JSObject*)argv[-2]))
00989         return JS_FALSE;
00990 
00991     PRE_HELPER_STUB
00992     Call(wrapper, cx, obj, argc, argv, rval, &retval);
00993     POST_HELPER_STUB
00994 }
00995 
00996 JS_STATIC_DLL_CALLBACK(JSBool)
00997 XPC_WN_Helper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
00998                         jsval *rval)
00999 {
01000     // this is a hack to get the obj of the actual object not the object
01001     // that JS thinks is the 'this' (which it passes as 'obj').
01002     if(!(obj = (JSObject*)argv[-2]))
01003         return JS_FALSE;
01004 
01005     PRE_HELPER_STUB
01006     Construct(wrapper, cx, obj, argc, argv, rval, &retval);
01007     POST_HELPER_STUB
01008 }
01009 
01010 JS_STATIC_DLL_CALLBACK(JSBool)
01011 XPC_WN_Helper_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
01012 {
01013     PRE_HELPER_STUB
01014     HasInstance(wrapper, cx, obj, v, bp, &retval);
01015     POST_HELPER_STUB
01016 }
01017 
01018 JS_STATIC_DLL_CALLBACK(void)
01019 XPC_WN_Helper_Finalize(JSContext *cx, JSObject *obj)
01020 {
01021     XPCWrappedNative* wrapper = (XPCWrappedNative*) JS_GetPrivate(cx, obj);
01022     if(!wrapper)
01023         return;
01024     wrapper->GetScriptableCallback()->Finalize(wrapper, cx, obj);
01025     wrapper->FlatJSObjectFinalized(cx, obj);
01026 }
01027 
01028 JS_STATIC_DLL_CALLBACK(uint32)
01029 XPC_WN_Helper_Mark(JSContext *cx, JSObject *obj, void *arg)
01030 {
01031     PRUint32 ignored;
01032     XPCWrappedNative* wrapper =
01033         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
01034     if(wrapper && wrapper->IsValid())
01035     {
01036         wrapper->GetScriptableCallback()->Mark(wrapper, cx, obj, arg, &ignored);
01037         xpc_MarkForValidWrapper(cx, wrapper, arg);
01038     }
01039     return (uint32) ignored;
01040 }
01041 
01042 JS_STATIC_DLL_CALLBACK(JSBool)
01043 XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
01044                          JSObject **objp)
01045 {
01046     CHECK_IDVAL(cx, idval);
01047 
01048     XPCCallContext ccx(JS_CALLER, cx, obj);
01049     XPCWrappedNative* wrapper = ccx.GetWrapper();
01050     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
01051 
01052     jsval old = ccx.SetResolveName(idval);
01053 
01054     nsresult rv = NS_OK;
01055     JSBool retval = JS_TRUE;
01056     JSObject* obj2FromScriptable = nsnull;
01057 
01058     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
01059     if(si && si->GetFlags().WantNewResolve())
01060     {
01061         XPCWrappedNative* oldResolvingWrapper;
01062         JSBool allowPropMods = si->GetFlags().AllowPropModsDuringResolve();
01063 
01064         if(allowPropMods)
01065             oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper);
01066 
01067         rv = si->GetCallback()->NewResolve(wrapper, cx, obj, idval, flags,
01068                                              &obj2FromScriptable, &retval);
01069 
01070         if(allowPropMods)
01071             (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
01072     }
01073 
01074     old = ccx.SetResolveName(old);
01075     NS_ASSERTION(old == idval, "bad nest");
01076 
01077     if(NS_FAILED(rv))
01078     {
01079         return Throw(rv, cx);
01080     }
01081 
01082     if(obj2FromScriptable)
01083     {
01084         *objp = obj2FromScriptable;
01085     }
01086     else if(wrapper->HasMutatedSet())
01087     {
01088         // We are here if scriptable did not resolve this property and
01089         // it *might* be in the instance set but not the proto set.
01090 
01091         XPCNativeSet* set = wrapper->GetSet();
01092         XPCNativeSet* protoSet = wrapper->HasProto() ?
01093                                     wrapper->GetProto()->GetSet() : nsnull;
01094         XPCNativeMember* member;
01095         XPCNativeInterface* iface;
01096         JSBool IsLocal;
01097 
01098         if(set->FindMember(idval, &member, &iface, protoSet, &IsLocal) &&
01099            IsLocal)
01100         {
01101             XPCWrappedNative* oldResolvingWrapper;
01102 
01103             XPCNativeScriptableFlags siFlags(0);
01104             if(si)
01105                 siFlags = si->GetFlags();
01106 
01107             uintN enumFlag =
01108                 siFlags.DontEnumStaticProps() ? 0 : JSPROP_ENUMERATE;
01109 
01110             XPCWrappedNative* wrapperForInterfaceNames =
01111                 siFlags.DontReflectInterfaceNames() ? nsnull : wrapper;
01112 
01113             JSBool resolved;
01114             oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper);
01115             retval = DefinePropertyIfFound(ccx, obj, idval,
01116                                            set, iface, member,
01117                                            wrapper->GetScope(),
01118                                            JS_FALSE,
01119                                            wrapperForInterfaceNames,
01120                                            nsnull, si,
01121                                            enumFlag, &resolved);
01122             (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
01123             if(retval && resolved)
01124                 *objp = obj;
01125         }
01126     }
01127 
01128     return retval;
01129 }
01130 
01131 /***************************************************************************/
01132 
01133 extern "C" JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;
01134 
01135 static JSObjectOps XPC_WN_WithCall_JSOps;
01136 static JSObjectOps XPC_WN_NoCall_JSOps;
01137 
01138 /*
01139     Here are the enumerator cases:
01140 
01141     set jsclass enumerate to stub (unless noted otherwise)
01142 
01143     if( helper wants new enumerate )
01144         if( DONT_ENUM_STATICS )
01145             forward to scriptable enumerate
01146         else
01147             if( set not mutated )
01148                 forward to scriptable enumerate
01149             else
01150                 call shared enumerate
01151                 forward to scriptable enumerate
01152     else if( helper wants old enumerate )
01153         use this JSOp
01154         if( DONT_ENUM_STATICS )
01155             call scriptable enumerate
01156             call stub
01157         else
01158             if( set not mutated )
01159                 call scriptable enumerate
01160                 call stub
01161             else
01162                 call shared enumerate
01163                 call scriptable enumerate
01164                 call stub
01165 
01166     else //... if( helper wants NO enumerate )
01167         if( DONT_ENUM_STATICS )
01168             use enumerate stub - don't use this JSOp thing at all
01169         else
01170             do shared enumerate - don't use this JSOp thing at all
01171 */
01172 
01173 JS_STATIC_DLL_CALLBACK(JSBool)
01174 XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
01175                       jsval *statep, jsid *idp)
01176 {
01177     XPCCallContext ccx(JS_CALLER, cx, obj);
01178     XPCWrappedNative* wrapper = ccx.GetWrapper();
01179     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
01180 
01181     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
01182     if(!si)
01183         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
01184 
01185     PRBool retval = JS_TRUE;
01186     nsresult rv;
01187 
01188     if(si->GetFlags().WantNewEnumerate())
01189     {
01190         if(enum_op == JSENUMERATE_INIT &&
01191            !si->GetFlags().DontEnumStaticProps() &&
01192            wrapper->HasMutatedSet() &&
01193            !XPC_WN_Shared_Enumerate(cx, obj))
01194         {
01195             *statep = JSVAL_NULL;
01196             return JS_FALSE;
01197         }
01198 
01199         // XXX Might we really need to wrap this call and *also* call
01200         // js_ObjectOps.enumerate ???
01201 
01202         rv = si->GetCallback()->
01203             NewEnumerate(wrapper, cx, obj, enum_op, statep, idp, &retval);
01204         
01205         if(enum_op == JSENUMERATE_INIT && (NS_FAILED(rv) || !retval))
01206             *statep = JSVAL_NULL;
01207         
01208         if(NS_FAILED(rv))
01209             return Throw(rv, cx);
01210         return retval;
01211     }
01212 
01213     if(si->GetFlags().WantEnumerate())
01214     {
01215         if(enum_op == JSENUMERATE_INIT)
01216         {
01217             if(!si->GetFlags().DontEnumStaticProps() &&
01218                wrapper->HasMutatedSet() &&
01219                !XPC_WN_Shared_Enumerate(cx, obj))
01220             {
01221                 *statep = JSVAL_NULL;
01222                 return JS_FALSE;
01223             }
01224             rv = si->GetCallback()->
01225                 Enumerate(wrapper, cx, obj, &retval);
01226 
01227             if(NS_FAILED(rv) || !retval)
01228                 *statep = JSVAL_NULL;
01229 
01230             if(NS_FAILED(rv))
01231                 return Throw(rv, cx);
01232             if(!retval)
01233                 return JS_FALSE;
01234             // Then fall through and call js_ObjectOps.enumerate...
01235         }
01236     }
01237 
01238     // else call js_ObjectOps.enumerate...
01239 
01240     return js_ObjectOps.enumerate(cx, obj, enum_op, statep, idp);
01241 }
01242 
01243 JS_STATIC_DLL_CALLBACK(void)
01244 XPC_WN_JSOp_Clear(JSContext *cx, JSObject *obj)
01245 {
01246     // If our scope is cleared, make sure we clear the scope of our
01247     // native wrapper as well.
01248     XPCWrappedNative *wrapper =
01249         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
01250 
01251     if(wrapper && wrapper->IsValid())
01252     {
01253         XPCNativeWrapper::ClearWrappedNativeScopes(cx, wrapper);
01254     }
01255 
01256     js_ObjectOps.clear(cx, obj);
01257 }
01258 
01259 JSObjectOps * JS_DLL_CALLBACK
01260 XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz)
01261 {
01262     return &XPC_WN_NoCall_JSOps;
01263 }
01264 
01265 JSObjectOps * JS_DLL_CALLBACK
01266 XPC_WN_GetObjectOpsWithCall(JSContext *cx, JSClass *clazz)
01267 {
01268     return &XPC_WN_WithCall_JSOps;
01269 }
01270 
01271 JSBool xpc_InitWrappedNativeJSOps()
01272 {
01273     if(!XPC_WN_NoCall_JSOps.newObjectMap)
01274     {
01275         memcpy(&XPC_WN_NoCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
01276         XPC_WN_NoCall_JSOps.enumerate = XPC_WN_JSOp_Enumerate;
01277 
01278         memcpy(&XPC_WN_WithCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
01279         XPC_WN_WithCall_JSOps.enumerate = XPC_WN_JSOp_Enumerate;
01280         XPC_WN_WithCall_JSOps.clear = XPC_WN_JSOp_Clear;
01281 
01282         XPC_WN_NoCall_JSOps.call = nsnull;
01283         XPC_WN_NoCall_JSOps.construct = nsnull;
01284         XPC_WN_NoCall_JSOps.clear = XPC_WN_JSOp_Clear;
01285     }
01286     return JS_TRUE;
01287 }
01288 
01289 /***************************************************************************/
01290 
01291 // static
01292 XPCNativeScriptableInfo*
01293 XPCNativeScriptableInfo::Construct(XPCCallContext& ccx,
01294                                    JSBool isGlobal,
01295                                    const XPCNativeScriptableCreateInfo* sci)
01296 {
01297     NS_ASSERTION(sci, "bad param");
01298     NS_ASSERTION(sci->GetCallback(), "bad param");
01299 
01300     XPCNativeScriptableInfo* newObj =
01301         new XPCNativeScriptableInfo(sci->GetCallback());
01302     if(!newObj)
01303         return nsnull;
01304 
01305     char* name = nsnull;
01306     if(NS_FAILED(sci->GetCallback()->GetClassName(&name)) || !name)
01307     {
01308         delete newObj;
01309         return nsnull;
01310     }
01311 
01312     JSBool success;
01313 
01314     XPCJSRuntime* rt = ccx.GetRuntime();
01315     XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap();
01316     {   // scoped lock
01317         XPCAutoLock lock(rt->GetMapLock());
01318         success = map->GetNewOrUsed(sci->GetFlags(), name, isGlobal, newObj);
01319     }
01320 
01321     if(!success)
01322     {
01323         delete newObj;
01324         return nsnull;
01325     }
01326 
01327     return newObj;
01328 }
01329 
01330 void
01331 XPCNativeScriptableShared::PopulateJSClass(JSBool isGlobal)
01332 {
01333     NS_ASSERTION(mJSClass.base.name, "bad state!");
01334 
01335     mJSClass.base.flags = JSCLASS_HAS_PRIVATE |
01336                           JSCLASS_PRIVATE_IS_NSISUPPORTS |
01337                           JSCLASS_NEW_RESOLVE |
01338                           JSCLASS_IS_EXTENDED;
01339 
01340     if(isGlobal)
01341         mJSClass.base.flags |= JSCLASS_GLOBAL_FLAGS;
01342 
01343     if(mFlags.WantAddProperty())
01344         mJSClass.base.addProperty = XPC_WN_Helper_AddProperty;
01345     else if(mFlags.UseJSStubForAddProperty())
01346         mJSClass.base.addProperty = JS_PropertyStub;
01347     else if(mFlags.AllowPropModsDuringResolve())
01348         mJSClass.base.addProperty = XPC_WN_MaybeResolvingPropertyStub;
01349     else
01350         mJSClass.base.addProperty = XPC_WN_CannotModifyPropertyStub;
01351 
01352     if(mFlags.WantDelProperty())
01353         mJSClass.base.delProperty = XPC_WN_Helper_DelProperty;
01354     else if(mFlags.UseJSStubForDelProperty())
01355         mJSClass.base.delProperty = JS_PropertyStub;
01356     else if(mFlags.AllowPropModsDuringResolve())
01357         mJSClass.base.delProperty = XPC_WN_MaybeResolvingPropertyStub;
01358     else
01359         mJSClass.base.delProperty = XPC_WN_CannotModifyPropertyStub;
01360 
01361     if(mFlags.WantGetProperty())
01362         mJSClass.base.getProperty = XPC_WN_Helper_GetProperty;
01363     else
01364         mJSClass.base.getProperty = JS_PropertyStub;
01365 
01366     if(mFlags.WantSetProperty())
01367         mJSClass.base.setProperty = XPC_WN_Helper_SetProperty;
01368     else if(mFlags.UseJSStubForSetProperty())
01369         mJSClass.base.setProperty = JS_PropertyStub;
01370     else if(mFlags.AllowPropModsDuringResolve())
01371         mJSClass.base.setProperty = XPC_WN_MaybeResolvingPropertyStub;
01372     else
01373         mJSClass.base.setProperty = XPC_WN_CannotModifyPropertyStub;
01374 
01375     // We figure out most of the enumerate strategy at call time.
01376 
01377     if(mFlags.WantNewEnumerate() || mFlags.WantEnumerate() ||
01378        mFlags.DontEnumStaticProps())
01379         mJSClass.base.enumerate = JS_EnumerateStub;
01380     else
01381         mJSClass.base.enumerate = XPC_WN_Shared_Enumerate;
01382 
01383     // We have to figure out resolve strategy at call time
01384     mJSClass.base.resolve = (JSResolveOp) XPC_WN_Helper_NewResolve;
01385 
01386     if(mFlags.WantConvert())
01387         mJSClass.base.convert = XPC_WN_Helper_Convert;
01388     else
01389         mJSClass.base.convert = XPC_WN_Shared_Convert;
01390 
01391     if(mFlags.WantFinalize())
01392         mJSClass.base.finalize = XPC_WN_Helper_Finalize;
01393     else
01394         mJSClass.base.finalize = XPC_WN_NoHelper_Finalize;
01395 
01396     // We let the rest default to nsnull unless the helper wants them...
01397     if(mFlags.WantCheckAccess())
01398         mJSClass.base.checkAccess = XPC_WN_Helper_CheckAccess;
01399 
01400     // Note that we *must* set
01401     //   mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsNoCall
01402     // or
01403     //   mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsWithCall
01404     // (even for the cases were it does not do much) because with these
01405     // dynamically generated JSClasses, the code in
01406     // XPCWrappedNative::GetWrappedNativeOfJSObject() needs to look for
01407     // that this callback pointer in order to identify that a given
01408     // JSObject represents a wrapper.
01409 
01410     if(mFlags.WantCall() || mFlags.WantConstruct())
01411     {
01412         mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsWithCall;
01413         if(mFlags.WantCall())
01414             mJSClass.base.call = XPC_WN_Helper_Call;
01415         if(mFlags.WantConstruct())
01416             mJSClass.base.construct = XPC_WN_Helper_Construct;
01417     }
01418     else
01419     {
01420         mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsNoCall;
01421     }
01422 
01423     if(mFlags.WantHasInstance())
01424         mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance;
01425 
01426     if(mFlags.WantMark())
01427         mJSClass.base.mark = XPC_WN_Helper_Mark;
01428     else
01429         mJSClass.base.mark = XPC_WN_Shared_Mark;
01430 
01431     mJSClass.equality = XPC_WN_Equality;
01432     mJSClass.outerObject = XPC_WN_OuterObject;
01433     mJSClass.innerObject = XPC_WN_InnerObject;
01434 }
01435 
01436 /***************************************************************************/
01437 /***************************************************************************/
01438 
01439 JSBool JS_DLL_CALLBACK
01440 XPC_WN_CallMethod(JSContext *cx, JSObject *obj,
01441                   uintN argc, jsval *argv, jsval *vp)
01442 {
01443     NS_ASSERTION(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION, "bad function");
01444     JSObject* funobj = JSVAL_TO_OBJECT(argv[-2]);
01445     XPCCallContext ccx(JS_CALLER, cx, obj, funobj, 0, argc, argv, vp);
01446     XPCWrappedNative* wrapper = ccx.GetWrapper();
01447     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
01448 
01449     XPCNativeInterface* iface;
01450     XPCNativeMember*    member;
01451 
01452     if(!XPCNativeMember::GetCallInfo(ccx, funobj, &iface, &member))
01453         return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
01454     ccx.SetCallInfo(iface, member, JS_FALSE);
01455     return XPCWrappedNative::CallMethod(ccx);
01456 }
01457 
01458 JSBool JS_DLL_CALLBACK
01459 XPC_WN_GetterSetter(JSContext *cx, JSObject *obj,
01460                     uintN argc, jsval *argv, jsval *vp)
01461 {
01462     NS_ASSERTION(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION, "bad function");
01463     JSObject* funobj = JSVAL_TO_OBJECT(argv[-2]);
01464 
01465     XPCCallContext ccx(JS_CALLER, cx, obj, funobj);
01466     XPCWrappedNative* wrapper = ccx.GetWrapper();
01467     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
01468 
01469     XPCNativeInterface* iface;
01470     XPCNativeMember*    member;
01471 
01472     if(!XPCNativeMember::GetCallInfo(ccx, funobj, &iface, &member))
01473         return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
01474 
01475     ccx.SetArgsAndResultPtr(argc, argv, vp);
01476     if(argc)
01477     {
01478         ccx.SetCallInfo(iface, member, JS_TRUE);
01479         JSBool retval = XPCWrappedNative::SetAttribute(ccx);
01480         if(retval && vp)
01481             *vp = argv[0];
01482         return retval;
01483     }
01484     // else...
01485 
01486     ccx.SetCallInfo(iface, member, JS_FALSE);
01487     return XPCWrappedNative::GetAttribute(ccx);
01488 }
01489 
01490 /***************************************************************************/
01491 
01492 JS_STATIC_DLL_CALLBACK(JSBool)
01493 XPC_WN_Shared_Proto_Enumerate(JSContext *cx, JSObject *obj)
01494 {
01495     NS_ASSERTION(
01496         JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_Proto_JSClass, nsnull) ||
01497         JS_InstanceOf(cx, obj, &XPC_WN_NoMods_Proto_JSClass, nsnull),
01498                  "bad proto");
01499     XPCWrappedNativeProto* self = (XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
01500     if(!self)
01501         return JS_FALSE;
01502 
01503     if(self->GetScriptableInfo() &&
01504        self->GetScriptableInfo()->GetFlags().DontEnumStaticProps())
01505         return JS_TRUE;
01506 
01507     XPCNativeSet* set = self->GetSet();
01508     if(!set)
01509         return JS_FALSE;
01510 
01511     XPCCallContext ccx(JS_CALLER, cx);
01512     if(!ccx.IsValid())
01513         return JS_FALSE;
01514 
01515     PRUint16 interface_count = set->GetInterfaceCount();
01516     XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
01517     for(PRUint16 i = 0; i < interface_count; i++)
01518     {
01519         XPCNativeInterface* iface = interfaceArray[i];
01520         PRUint16 member_count = iface->GetMemberCount();
01521 
01522         for(PRUint16 k = 0; k < member_count; k++)
01523         {
01524             if(!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
01525                 return JS_FALSE;
01526         }
01527     }
01528 
01529     return JS_TRUE;
01530 }
01531 
01532 JS_STATIC_DLL_CALLBACK(JSBool)
01533 XPC_WN_Shared_Proto_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
01534 {
01535     // XXX ?
01536     return JS_TRUE;
01537 }
01538 
01539 JS_STATIC_DLL_CALLBACK(void)
01540 XPC_WN_Shared_Proto_Finalize(JSContext *cx, JSObject *obj)
01541 {
01542     // This can be null if xpc shutdown has already happened
01543     XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
01544     if(p)
01545         p->JSProtoObjectFinalized(cx, obj);
01546 }
01547 
01548 JS_STATIC_DLL_CALLBACK(uint32)
01549 XPC_WN_Shared_Proto_Mark(JSContext *cx, JSObject *obj, void *arg)
01550 {
01551     // This can be null if xpc shutdown has already happened
01552     XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
01553     if(p)
01554         MarkScopeJSObjects(cx, p->GetScope(), arg);
01555     return 1;
01556 }
01557 
01558 /*****************************************************/
01559 
01560 JS_STATIC_DLL_CALLBACK(JSBool)
01561 XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, JSObject *obj, jsval idval)
01562 {
01563     CHECK_IDVAL(cx, idval);
01564 
01565     NS_ASSERTION(
01566         JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_Proto_JSClass, nsnull),
01567                  "bad proto");
01568 
01569     XPCWrappedNativeProto* self = (XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
01570     if(!self)
01571         return JS_FALSE;
01572 
01573     XPCCallContext ccx(JS_CALLER, cx);
01574     if(!ccx.IsValid())
01575         return JS_FALSE;
01576 
01577     XPCNativeScriptableInfo* si = self->GetScriptableInfo();
01578     uintN enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ?
01579                                                 0 : JSPROP_ENUMERATE;
01580 
01581     return DefinePropertyIfFound(ccx, obj, idval,
01582                                  self->GetSet(), nsnull, nsnull,
01583                                  self->GetScope(),
01584                                  JS_TRUE, nsnull, nsnull, si,
01585                                  enumFlag, nsnull);
01586 }
01587 
01588 
01589 JSClass XPC_WN_ModsAllowed_Proto_JSClass = {
01590     "XPC_WN_ModsAllowed_Proto_JSClass", // name;
01591     JSCLASS_HAS_PRIVATE,                // flags;
01592 
01593     /* Mandatory non-null function pointer members. */
01594     JS_PropertyStub,                // addProperty;
01595     JS_PropertyStub,                // delProperty;
01596     JS_PropertyStub,                // getProperty;
01597     JS_PropertyStub,                // setProperty;
01598     XPC_WN_Shared_Proto_Enumerate,         // enumerate;
01599     XPC_WN_ModsAllowed_Proto_Resolve,      // resolve;
01600     XPC_WN_Shared_Proto_Convert,           // convert;
01601     XPC_WN_Shared_Proto_Finalize,          // finalize;
01602 
01603     /* Optionally non-null members start here. */
01604     nsnull,                         // getObjectOps;
01605     nsnull,                         // checkAccess;
01606     nsnull,                         // call;
01607     nsnull,                         // construct;
01608     nsnull,                         // xdrObject;
01609     nsnull,                         // hasInstance;
01610     XPC_WN_Shared_Proto_Mark,       // mark;
01611     nsnull                          // spare;
01612 };
01613 
01614 /***************************************************************************/
01615 
01616 JS_STATIC_DLL_CALLBACK(JSBool)
01617 XPC_WN_OnlyIWrite_Proto_PropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
01618 {
01619     CHECK_IDVAL(cx, idval);
01620 
01621     NS_ASSERTION(
01622         JS_InstanceOf(cx, obj, &XPC_WN_NoMods_Proto_JSClass, nsnull),
01623                  "bad proto");
01624 
01625     XPCWrappedNativeProto* self = (XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
01626     if(!self)
01627         return JS_FALSE;
01628 
01629     XPCCallContext ccx(JS_CALLER, cx);
01630     if(!ccx.IsValid())
01631         return JS_FALSE;
01632 
01633     // Allow XPConnect to add the property only
01634     if(ccx.GetResolveName() == idval)
01635         return JS_TRUE;
01636 
01637     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
01638 }
01639 
01640 JS_STATIC_DLL_CALLBACK(JSBool)
01641 XPC_WN_NoMods_Proto_Resolve(JSContext *cx, JSObject *obj, jsval idval)
01642 {
01643     CHECK_IDVAL(cx, idval);
01644 
01645     NS_ASSERTION(
01646         JS_InstanceOf(cx, obj, &XPC_WN_NoMods_Proto_JSClass, nsnull),
01647                  "bad proto");
01648 
01649     XPCWrappedNativeProto* self = (XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
01650     if(!self)
01651         return JS_FALSE;
01652 
01653     XPCCallContext ccx(JS_CALLER, cx);
01654     if(!ccx.IsValid())
01655         return JS_FALSE;
01656 
01657     XPCNativeScriptableInfo* si = self->GetScriptableInfo();
01658     uintN enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ?
01659                                                 0 : JSPROP_ENUMERATE;
01660 
01661     return DefinePropertyIfFound(ccx, obj, idval,
01662                                  self->GetSet(), nsnull, nsnull,
01663                                  self->GetScope(),
01664                                  JS_TRUE, nsnull, nsnull, si,
01665                                  JSPROP_READONLY |
01666                                  JSPROP_PERMANENT |
01667                                  enumFlag, nsnull);
01668 }
01669 
01670 JSClass XPC_WN_NoMods_Proto_JSClass = {
01671     "XPC_WN_NoMods_Proto_JSClass",      // name;
01672     JSCLASS_HAS_PRIVATE,                // flags;
01673 
01674     /* Mandatory non-null function pointer members. */
01675     XPC_WN_OnlyIWrite_Proto_PropertyStub,  // addProperty;
01676     XPC_WN_CannotModifyPropertyStub,       // delProperty;
01677     JS_PropertyStub,                       // getProperty;
01678     XPC_WN_OnlyIWrite_Proto_PropertyStub,  // setProperty;
01679     XPC_WN_Shared_Proto_Enumerate,         // enumerate;
01680     XPC_WN_NoMods_Proto_Resolve,           // resolve;
01681     XPC_WN_Shared_Proto_Convert,           // convert;
01682     XPC_WN_Shared_Proto_Finalize,          // finalize;
01683 
01684     /* Optionally non-null members start here. */
01685     nsnull,                         // getObjectOps;
01686     nsnull,                         // checkAccess;
01687     nsnull,                         // call;
01688     nsnull,                         // construct;
01689     nsnull,                         // xdrObject;
01690     nsnull,                         // hasInstance;
01691     XPC_WN_Shared_Proto_Mark,       // mark;
01692     nsnull                          // spare;
01693 };
01694 
01695 /***************************************************************************/
01696 
01697 JS_STATIC_DLL_CALLBACK(JSBool)
01698 XPC_WN_TearOff_Enumerate(JSContext *cx, JSObject *obj)
01699 {
01700     XPCCallContext ccx(JS_CALLER, cx, obj);
01701     XPCWrappedNative* wrapper = ccx.GetWrapper();
01702     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
01703 
01704     XPCWrappedNativeTearOff* to = ccx.GetTearOff();
01705     XPCNativeInterface* iface;
01706 
01707     if(!to || nsnull == (iface = to->GetInterface()))
01708         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
01709 
01710     PRUint16 member_count = iface->GetMemberCount();
01711     for(PRUint16 k = 0; k < member_count; k++)
01712     {
01713         if(!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
01714             return JS_FALSE;
01715     }
01716 
01717     return JS_TRUE;
01718 }
01719 
01720 JS_STATIC_DLL_CALLBACK(JSBool)
01721 XPC_WN_TearOff_Resolve(JSContext *cx, JSObject *obj, jsval idval)
01722 {
01723     CHECK_IDVAL(cx, idval);
01724 
01725     XPCCallContext ccx(JS_CALLER, cx, obj);
01726     XPCWrappedNative* wrapper = ccx.GetWrapper();
01727     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
01728 
01729     XPCWrappedNativeTearOff* to = ccx.GetTearOff();
01730     XPCNativeInterface* iface;
01731 
01732     if(!to || nsnull == (iface = to->GetInterface()))
01733         return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
01734 
01735     return DefinePropertyIfFound(ccx, obj, idval, nsnull, iface, nsnull,
01736                                  wrapper->GetScope(),
01737                                  JS_TRUE, nsnull, nsnull, nsnull,
01738                                  JSPROP_READONLY |
01739                                  JSPROP_PERMANENT |
01740                                  JSPROP_ENUMERATE, nsnull);
01741 }
01742 
01743 JS_STATIC_DLL_CALLBACK(void)
01744 XPC_WN_TearOff_Finalize(JSContext *cx, JSObject *obj)
01745 {
01746     XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
01747         JS_GetPrivate(cx, obj);
01748     if(!p)
01749         return;
01750     p->JSObjectFinalized();
01751 }
01752 
01753 JSClass XPC_WN_Tearoff_JSClass = {
01754     "WrappedNative_TearOff",            // name;
01755     JSCLASS_HAS_PRIVATE,                // flags;
01756 
01757     /* Mandatory non-null function pointer members. */
01758     XPC_WN_OnlyIWrite_PropertyStub,     // addProperty;
01759     XPC_WN_CannotModifyPropertyStub,    // delProperty;
01760     JS_PropertyStub,                    // getProperty;
01761     XPC_WN_OnlyIWrite_PropertyStub,     // setProperty;
01762     XPC_WN_TearOff_Enumerate,           // enumerate;
01763     XPC_WN_TearOff_Resolve,             // resolve;
01764     XPC_WN_Shared_Convert,              // convert;
01765     XPC_WN_TearOff_Finalize,            // finalize;
01766 
01767     /* Optionally non-null members start here. */
01768     nsnull,                         // getObjectOps;
01769     nsnull,                         // checkAccess;
01770     nsnull,                         // call;
01771     nsnull,                         // construct;
01772     nsnull,                         // xdrObject;
01773     nsnull,                         // hasInstance;
01774     nsnull,                         // mark;
01775     nsnull                          // spare;
01776 };
01777