LCOV - code coverage report
Current view: directory - js/xpconnect/src - XPCWrappedJSClass.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 777 576 74.1 %
Date: 2012-06-02 Functions: 49 31 63.3 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=78:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *   John Bandhauer <jband@netscape.com> (original author)
      27                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : /* Sharable code and data for wrapper around JSObjects. */
      44                 : 
      45                 : #include "xpcprivate.h"
      46                 : #include "nsArrayEnumerator.h"
      47                 : #include "nsWrapperCache.h"
      48                 : #include "XPCWrapper.h"
      49                 : #include "AccessCheck.h"
      50                 : #include "nsJSUtils.h"
      51                 : 
      52                 : #include "jsapi.h"
      53                 : 
      54         6654697 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
      55                 : 
      56                 : // the value of this variable is never used - we use its address as a sentinel
      57                 : static uint32_t zero_methods_descriptor;
      58                 : 
      59         1520912 : bool AutoScriptEvaluate::StartEvaluating(JSObject *scope, JSErrorReporter errorReporter)
      60                 : {
      61         1520912 :     NS_PRECONDITION(!mEvaluated, "AutoScriptEvaluate::Evaluate should only be called once");
      62                 : 
      63         1520912 :     if (!mJSContext)
      64               0 :         return true;
      65                 : 
      66         1520912 :     mEvaluated = true;
      67         1520912 :     if (!JS_GetErrorReporter(mJSContext)) {
      68              39 :         JS_SetErrorReporter(mJSContext, errorReporter);
      69              39 :         mErrorReporterSet = true;
      70                 :     }
      71                 : 
      72         1520912 :     JS_BeginRequest(mJSContext);
      73         1520912 :     if (!mEnterCompartment.enter(mJSContext, scope))
      74               0 :         return false;
      75                 : 
      76                 :     // Saving the exception state keeps us from interfering with another script
      77                 :     // that may also be running on this context.  This occurred first with the
      78                 :     // js debugger, as described in
      79                 :     // http://bugzilla.mozilla.org/show_bug.cgi?id=88130 but presumably could
      80                 :     // show up in any situation where a script calls into a wrapped js component
      81                 :     // on the same context, while the context has a nonzero exception state.
      82                 :     // Because JS_SaveExceptionState/JS_RestoreExceptionState use malloc
      83                 :     // and addroot, we avoid them if possible by returning null (as opposed to
      84                 :     // a JSExceptionState with no information) when there is no pending
      85                 :     // exception.
      86         1520912 :     if (JS_IsExceptionPending(mJSContext)) {
      87               1 :         mState = JS_SaveExceptionState(mJSContext);
      88               1 :         JS_ClearPendingException(mJSContext);
      89                 :     }
      90                 : 
      91         1520912 :     return true;
      92                 : }
      93                 : 
      94         3041824 : AutoScriptEvaluate::~AutoScriptEvaluate()
      95                 : {
      96         1520912 :     if (!mJSContext || !mEvaluated)
      97                 :         return;
      98         1520912 :     if (mState)
      99               1 :         JS_RestoreExceptionState(mJSContext, mState);
     100                 :     else
     101         1520911 :         JS_ClearPendingException(mJSContext);
     102                 : 
     103         1520912 :     JS_EndRequest(mJSContext);
     104                 : 
     105                 :     // If this is a JSContext that has a private context that provides a
     106                 :     // nsIXPCScriptNotify interface, then notify the object the script has
     107                 :     // been executed.
     108                 :     //
     109                 :     // Note: We rely on the rule that if any JSContext in our JSRuntime has
     110                 :     // private data that points to an nsISupports subclass, it has also set
     111                 :     // the JSOPTION_PRIVATE_IS_NSISUPPORTS option.
     112                 : 
     113         1520912 :     if (JS_GetOptions(mJSContext) & JSOPTION_PRIVATE_IS_NSISUPPORTS) {
     114                 :         nsCOMPtr<nsIXPCScriptNotify> scriptNotify =
     115                 :             do_QueryInterface(static_cast<nsISupports*>
     116               8 :                                          (JS_GetContextPrivate(mJSContext)));
     117               4 :         if (scriptNotify)
     118               0 :             scriptNotify->ScriptExecuted();
     119                 :     }
     120                 : 
     121         1520912 :     if (mErrorReporterSet)
     122              39 :         JS_SetErrorReporter(mJSContext, NULL);
     123         1520912 : }
     124                 : 
     125                 : // It turns out that some errors may be not worth reporting. So, this
     126                 : // function is factored out to manage that.
     127            6889 : JSBool xpc_IsReportableErrorCode(nsresult code)
     128                 : {
     129            6889 :     if (NS_SUCCEEDED(code))
     130               1 :         return false;
     131                 : 
     132            6888 :     switch (code) {
     133                 :         // Error codes that we don't want to report as errors...
     134                 :         // These generally indicate bad interface design AFAIC.
     135                 :         case NS_ERROR_FACTORY_REGISTER_AGAIN:
     136                 :         case NS_BASE_STREAM_WOULD_BLOCK:
     137               0 :             return false;
     138                 :     }
     139                 : 
     140            6888 :     return true;
     141                 : }
     142                 : 
     143                 : // static
     144                 : nsresult
     145          156779 : nsXPCWrappedJSClass::GetNewOrUsed(XPCCallContext& ccx, REFNSIID aIID,
     146                 :                                   nsXPCWrappedJSClass** resultClazz)
     147                 : {
     148          156779 :     nsXPCWrappedJSClass* clazz = nsnull;
     149          156779 :     XPCJSRuntime* rt = ccx.GetRuntime();
     150                 : 
     151                 :     {   // scoped lock
     152          313558 :         XPCAutoLock lock(rt->GetMapLock());
     153          156779 :         IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
     154          156779 :         clazz = map->Find(aIID);
     155          156779 :         NS_IF_ADDREF(clazz);
     156                 :     }
     157                 : 
     158          156779 :     if (!clazz) {
     159           65024 :         nsCOMPtr<nsIInterfaceInfo> info;
     160           32512 :         ccx.GetXPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
     161           32512 :         if (info) {
     162                 :             bool canScript, isBuiltin;
     163          130048 :             if (NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
     164           65024 :                 NS_SUCCEEDED(info->IsBuiltinClass(&isBuiltin)) && !isBuiltin &&
     165           32512 :                 nsXPConnect::IsISupportsDescendant(info)) {
     166           65024 :                 clazz = new nsXPCWrappedJSClass(ccx, aIID, info);
     167           32512 :                 if (clazz && !clazz->mDescriptors)
     168               0 :                     NS_RELEASE(clazz);  // sets clazz to nsnull
     169                 :             }
     170                 :         }
     171                 :     }
     172          156779 :     *resultClazz = clazz;
     173          156779 :     return NS_OK;
     174                 : }
     175                 : 
     176           32512 : nsXPCWrappedJSClass::nsXPCWrappedJSClass(XPCCallContext& ccx, REFNSIID aIID,
     177                 :                                          nsIInterfaceInfo* aInfo)
     178           32512 :     : mRuntime(ccx.GetRuntime()),
     179                 :       mInfo(aInfo),
     180                 :       mName(nsnull),
     181                 :       mIID(aIID),
     182           65024 :       mDescriptors(nsnull)
     183                 : {
     184           32512 :     NS_ADDREF(mInfo);
     185           32512 :     NS_ADDREF_THIS();
     186                 : 
     187                 :     {   // scoped lock
     188           65024 :         XPCAutoLock lock(mRuntime->GetMapLock());
     189           32512 :         mRuntime->GetWrappedJSClassMap()->Add(this);
     190                 :     }
     191                 : 
     192                 :     uint16_t methodCount;
     193           32512 :     if (NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) {
     194           32512 :         if (methodCount) {
     195           32512 :             int wordCount = (methodCount/32)+1;
     196           65024 :             if (nsnull != (mDescriptors = new uint32_t[wordCount])) {
     197                 :                 int i;
     198                 :                 // init flags to 0;
     199           65124 :                 for (i = wordCount-1; i >= 0; i--)
     200           32612 :                     mDescriptors[i] = 0;
     201                 : 
     202          431204 :                 for (i = 0; i < methodCount; i++) {
     203                 :                     const nsXPTMethodInfo* info;
     204          183090 :                     if (NS_SUCCEEDED(mInfo->GetMethodInfo(i, &info)))
     205          183090 :                         SetReflectable(i, XPCConvert::IsMethodReflectable(*info));
     206                 :                     else {
     207               0 :                         delete [] mDescriptors;
     208               0 :                         mDescriptors = nsnull;
     209               0 :                         break;
     210                 :                     }
     211                 :                 }
     212                 :             }
     213                 :         } else {
     214               0 :             mDescriptors = &zero_methods_descriptor;
     215                 :         }
     216                 :     }
     217           32512 : }
     218                 : 
     219           64996 : nsXPCWrappedJSClass::~nsXPCWrappedJSClass()
     220                 : {
     221           32498 :     if (mDescriptors && mDescriptors != &zero_methods_descriptor)
     222           32498 :         delete [] mDescriptors;
     223           32498 :     if (mRuntime)
     224                 :     {   // scoped lock
     225           64996 :         XPCAutoLock lock(mRuntime->GetMapLock());
     226           32498 :         mRuntime->GetWrappedJSClassMap()->Remove(this);
     227                 :     }
     228           32498 :     if (mName)
     229            2031 :         nsMemory::Free(mName);
     230           32498 :     NS_IF_RELEASE(mInfo);
     231          129992 : }
     232                 : 
     233                 : JSObject*
     234          295342 : nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
     235                 :                                                   JSObject* jsobj,
     236                 :                                                   REFNSIID aIID)
     237                 : {
     238          295342 :     JSContext* cx = ccx.GetJSContext();
     239                 :     JSObject* id;
     240                 :     jsval retval;
     241                 :     JSObject* retObj;
     242          295342 :     JSBool success = false;
     243                 :     jsid funid;
     244                 :     jsval fun;
     245                 : 
     246                 :     // Don't call the actual function on a content object. We'll determine
     247                 :     // whether or not a content object is capable of implementing the
     248                 :     // interface (i.e. whether the interface is scriptable) and most content
     249                 :     // objects don't have QI implementations anyway. Also see bug 503926.
     250          590684 :     if (XPCPerThreadData::IsMainThread(ccx) &&
     251          295342 :         !xpc::AccessCheck::isChrome(js::GetObjectCompartment(jsobj))) {
     252               0 :         return nsnull;
     253                 :     }
     254                 : 
     255                 :     // OK, it looks like we'll be calling into JS code.
     256          590684 :     AutoScriptEvaluate scriptEval(cx);
     257                 : 
     258                 :     // XXX we should install an error reporter that will send reports to
     259                 :     // the JS error console service.
     260          295342 :     if (!scriptEval.StartEvaluating(jsobj))
     261               0 :         return nsnull;
     262                 : 
     263                 :     // check upfront for the existence of the function property
     264          295342 :     funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
     265          295342 :     if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
     266          139437 :         return nsnull;
     267                 : 
     268                 :     // protect fun so that we're sure it's alive when we call it
     269          311810 :     AUTO_MARK_JSVAL(ccx, fun);
     270                 : 
     271                 :     // Ensure that we are asking for a scriptable interface.
     272                 :     // NB:  It's important for security that this check is here rather
     273                 :     // than later, since it prevents untrusted objects from implementing
     274                 :     // some interfaces in JS and aggregating a trusted object to
     275                 :     // implement intentionally (for security) unscriptable interfaces.
     276                 :     // We so often ask for nsISupports that we can short-circuit the test...
     277          155905 :     if (!aIID.Equals(NS_GET_IID(nsISupports))) {
     278          157042 :         nsCOMPtr<nsIInterfaceInfo> info;
     279           78521 :         ccx.GetXPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
     280           78521 :         if (!info)
     281              55 :             return nsnull;
     282                 :         bool canScript, isBuiltin;
     283          140520 :         if (NS_FAILED(info->IsScriptable(&canScript)) || !canScript ||
     284           62054 :             NS_FAILED(info->IsBuiltinClass(&isBuiltin)) || isBuiltin)
     285           16412 :             return nsnull;
     286                 :     }
     287                 : 
     288          139438 :     id = xpc_NewIDObject(cx, jsobj, aIID);
     289          139438 :     if (id) {
     290                 :         // Throwing NS_NOINTERFACE is the prescribed way to fail QI from JS. It
     291                 :         // is not an exception that is ever worth reporting, but we don't want
     292                 :         // to eat all exceptions either.
     293                 : 
     294                 :         uint32_t oldOpts =
     295          139438 :           JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT);
     296                 : 
     297          139438 :         jsval args[1] = {OBJECT_TO_JSVAL(id)};
     298          139438 :         success = JS_CallFunctionValue(cx, jsobj, fun, 1, args, &retval);
     299                 : 
     300          139438 :         JS_SetOptions(cx, oldOpts);
     301                 : 
     302          139438 :         if (!success) {
     303           50703 :             NS_ASSERTION(JS_IsExceptionPending(cx),
     304                 :                          "JS failed without setting an exception!");
     305                 : 
     306           50703 :             jsval jsexception = JSVAL_NULL;
     307          101406 :             AUTO_MARK_JSVAL(ccx, &jsexception);
     308                 : 
     309           50703 :             if (JS_GetPendingException(cx, &jsexception)) {
     310                 :                 nsresult rv;
     311           50703 :                 if (JSVAL_IS_OBJECT(jsexception)) {
     312                 :                     // XPConnect may have constructed an object to represent a
     313                 :                     // C++ QI failure. See if that is the case.
     314             730 :                     nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     315                 : 
     316             365 :                     nsXPConnect::GetXPConnect()->
     317                 :                         GetWrappedNativeOfJSObject(ccx,
     318                 :                                                    JSVAL_TO_OBJECT(jsexception),
     319             365 :                                                    getter_AddRefs(wrapper));
     320                 : 
     321             365 :                     if (wrapper) {
     322                 :                         nsCOMPtr<nsIException> exception =
     323               0 :                             do_QueryWrappedNative(wrapper);
     324               0 :                         if (exception &&
     325               0 :                             NS_SUCCEEDED(exception->GetResult(&rv)) &&
     326                 :                             rv == NS_NOINTERFACE) {
     327               0 :                             JS_ClearPendingException(cx);
     328                 :                         }
     329                 :                     }
     330           50338 :                 } else if (JSVAL_IS_NUMBER(jsexception)) {
     331                 :                     // JS often throws an nsresult.
     332           50338 :                     if (JSVAL_IS_DOUBLE(jsexception))
     333           50338 :                         rv = (nsresult)(JSVAL_TO_DOUBLE(jsexception));
     334                 :                     else
     335               0 :                         rv = (nsresult)(JSVAL_TO_INT(jsexception));
     336                 : 
     337           50338 :                     if (rv == NS_NOINTERFACE)
     338           50338 :                         JS_ClearPendingException(cx);
     339                 :                 }
     340                 :             }
     341                 : 
     342                 :             // Don't report if reporting was disabled by someone else.
     343           50703 :             if (!(oldOpts & JSOPTION_DONT_REPORT_UNCAUGHT))
     344           11463 :                 JS_ReportPendingException(cx);
     345                 :         }
     346                 :     }
     347                 : 
     348          139438 :     if (success)
     349           88735 :         success = JS_ValueToObject(cx, retval, &retObj);
     350                 : 
     351          139438 :     return success ? retObj : nsnull;
     352                 : }
     353                 : 
     354                 : /***************************************************************************/
     355                 : 
     356                 : static JSBool
     357               6 : GetNamedPropertyAsVariantRaw(XPCCallContext& ccx,
     358                 :                              JSObject* aJSObj,
     359                 :                              jsid aName,
     360                 :                              nsIVariant** aResult,
     361                 :                              nsresult* pErr)
     362                 : {
     363               6 :     nsXPTType type = nsXPTType((uint8_t)TD_INTERFACE_TYPE);
     364                 :     jsval val;
     365                 : 
     366               6 :     return JS_GetPropertyById(ccx, aJSObj, aName, &val) &&
     367                 :            // Note that this always takes the T_INTERFACE path through
     368                 :            // JSData2Native, so the value passed for useAllocator
     369                 :            // doesn't really matter. We pass true for consistency.
     370                 :            XPCConvert::JSData2Native(ccx, aResult, val, type, true,
     371               6 :                                      &NS_GET_IID(nsIVariant), pErr);
     372                 : }
     373                 : 
     374                 : // static
     375                 : nsresult
     376               6 : nsXPCWrappedJSClass::GetNamedPropertyAsVariant(XPCCallContext& ccx,
     377                 :                                                JSObject* aJSObj,
     378                 :                                                const nsAString& aName,
     379                 :                                                nsIVariant** aResult)
     380                 : {
     381               6 :     JSContext* cx = ccx.GetJSContext();
     382                 :     JSBool ok;
     383                 :     jsid id;
     384               6 :     nsresult rv = NS_ERROR_FAILURE;
     385                 : 
     386              12 :     AutoScriptEvaluate scriptEval(cx);
     387               6 :     if (!scriptEval.StartEvaluating(aJSObj))
     388               0 :         return NS_ERROR_FAILURE;
     389                 : 
     390                 :     // Wrap the string in a jsval after the AutoScriptEvaluate, so that the
     391                 :     // resulting value ends up in the correct compartment.
     392                 :     nsStringBuffer* buf;
     393               6 :     jsval jsstr = XPCStringConvert::ReadableToJSVal(ccx, aName, &buf);
     394               6 :     if (JSVAL_IS_NULL(jsstr))
     395               0 :         return NS_ERROR_OUT_OF_MEMORY;
     396               6 :     if (buf)
     397               0 :         buf->AddRef();
     398                 : 
     399               6 :     ok = JS_ValueToId(cx, jsstr, &id) &&
     400               6 :          GetNamedPropertyAsVariantRaw(ccx, aJSObj, id, aResult, &rv);
     401                 : 
     402               6 :     return ok ? NS_OK : NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
     403                 : }
     404                 : 
     405                 : /***************************************************************************/
     406                 : 
     407                 : // static
     408                 : nsresult
     409               0 : nsXPCWrappedJSClass::BuildPropertyEnumerator(XPCCallContext& ccx,
     410                 :                                              JSObject* aJSObj,
     411                 :                                              nsISimpleEnumerator** aEnumerate)
     412                 : {
     413               0 :     JSContext* cx = ccx.GetJSContext();
     414                 : 
     415               0 :     AutoScriptEvaluate scriptEval(cx);
     416               0 :     if (!scriptEval.StartEvaluating(aJSObj))
     417               0 :         return NS_ERROR_FAILURE;
     418                 : 
     419               0 :     JS::AutoIdArray idArray(cx, JS_Enumerate(cx, aJSObj));
     420               0 :     if (!idArray)
     421               0 :         return NS_ERROR_FAILURE;
     422                 : 
     423               0 :     nsCOMArray<nsIProperty> propertyArray(idArray.length());
     424               0 :     for (size_t i = 0; i < idArray.length(); i++) {
     425               0 :         jsid idName = idArray[i];
     426                 : 
     427               0 :         nsCOMPtr<nsIVariant> value;
     428                 :         nsresult rv;
     429               0 :         if (!GetNamedPropertyAsVariantRaw(ccx, aJSObj, idName,
     430               0 :                                           getter_AddRefs(value), &rv)) {
     431               0 :             if (NS_FAILED(rv))
     432               0 :                 return rv;
     433               0 :             return NS_ERROR_FAILURE;
     434                 :         }
     435                 : 
     436                 :         jsval jsvalName;
     437               0 :         if (!JS_IdToValue(cx, idName, &jsvalName))
     438               0 :             return NS_ERROR_FAILURE;
     439                 : 
     440               0 :         JSString* name = JS_ValueToString(cx, jsvalName);
     441               0 :         if (!name)
     442               0 :             return NS_ERROR_FAILURE;
     443                 : 
     444                 :         size_t length;
     445               0 :         const jschar *chars = JS_GetStringCharsAndLength(cx, name, &length);
     446               0 :         if (!chars)
     447               0 :             return NS_ERROR_FAILURE;
     448                 : 
     449                 :         nsCOMPtr<nsIProperty> property =
     450               0 :             new xpcProperty(chars, (PRUint32) length, value);
     451                 : 
     452               0 :         if (!propertyArray.AppendObject(property))
     453               0 :             return NS_ERROR_FAILURE;
     454                 :     }
     455                 : 
     456               0 :     return NS_NewArrayEnumerator(aEnumerate, propertyArray);
     457                 : }
     458                 : 
     459                 : /***************************************************************************/
     460                 : 
     461               0 : NS_IMPL_ISUPPORTS1(xpcProperty, nsIProperty)
     462                 : 
     463               0 : xpcProperty::xpcProperty(const PRUnichar* aName, PRUint32 aNameLen,
     464                 :                          nsIVariant* aValue)
     465               0 :     : mName(aName, aNameLen), mValue(aValue)
     466                 : {
     467               0 : }
     468                 : 
     469                 : /* readonly attribute AString name; */
     470               0 : NS_IMETHODIMP xpcProperty::GetName(nsAString & aName)
     471                 : {
     472               0 :     aName.Assign(mName);
     473               0 :     return NS_OK;
     474                 : }
     475                 : 
     476                 : /* readonly attribute nsIVariant value; */
     477               0 : NS_IMETHODIMP xpcProperty::GetValue(nsIVariant * *aValue)
     478                 : {
     479               0 :     NS_ADDREF(*aValue = mValue);
     480               0 :     return NS_OK;
     481                 : }
     482                 : 
     483                 : /***************************************************************************/
     484                 : // This 'WrappedJSIdentity' class and singleton allow us to figure out if
     485                 : // any given nsISupports* is implemented by a WrappedJS object. This is done
     486                 : // using a QueryInterface call on the interface pointer with our ID. If
     487                 : // that call returns NS_OK and the pointer is to our singleton, then the
     488                 : // interface must be implemented by a WrappedJS object. NOTE: the
     489                 : // 'WrappedJSIdentity' object is not a real XPCOM object and should not be
     490                 : // used for anything else (hence it is declared in this implementation file).
     491                 : 
     492                 : // {5C5C3BB0-A9BA-11d2-BA64-00805F8A5DD7}
     493                 : #define NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID                           \
     494                 : { 0x5c5c3bb0, 0xa9ba, 0x11d2,                                                 \
     495                 :   { 0xba, 0x64, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
     496                 : 
     497                 : class WrappedJSIdentity
     498                 : {
     499                 :     // no instance methods...
     500                 : public:
     501                 :     NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
     502                 : 
     503           34156 :     static void* GetSingleton()
     504                 :     {
     505                 :         static WrappedJSIdentity* singleton = nsnull;
     506           34156 :         if (!singleton)
     507             556 :             singleton = new WrappedJSIdentity();
     508           34156 :         return (void*) singleton;
     509                 :     }
     510                 : };
     511                 : 
     512                 : NS_DEFINE_STATIC_IID_ACCESSOR(WrappedJSIdentity,
     513                 :                               NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
     514                 : 
     515                 : /***************************************************************************/
     516                 : 
     517                 : // static
     518                 : JSBool
     519         1225340 : nsXPCWrappedJSClass::IsWrappedJS(nsISupports* aPtr)
     520                 : {
     521                 :     void* result;
     522         1225340 :     NS_PRECONDITION(aPtr, "null pointer");
     523                 :     return aPtr &&
     524         1225340 :            NS_OK == aPtr->QueryInterface(NS_GET_IID(WrappedJSIdentity), &result) &&
     525         2450680 :            result == WrappedJSIdentity::GetSingleton();
     526                 : }
     527                 : 
     528                 : static JSContext *
     529         1849649 : GetContextFromObject(JSObject *obj)
     530                 : {
     531                 :     // Don't stomp over a running context.
     532                 :     XPCJSContextStack* stack =
     533         1849649 :         XPCPerThreadData::GetData(nsnull)->GetJSContextStack();
     534                 : 
     535         1849649 :     if (stack && stack->Peek())
     536         1755358 :         return nsnull;
     537                 : 
     538                 :     // In order to get a context, we need a context.
     539          188582 :     XPCCallContext ccx(NATIVE_CALLER);
     540           94291 :     if (!ccx.IsValid())
     541               0 :         return nsnull;
     542                 : 
     543          188582 :     JSAutoEnterCompartment ac;
     544           94291 :     if (!ac.enter(ccx, obj))
     545               0 :         return nsnull;
     546                 :     XPCWrappedNativeScope* scope =
     547           94291 :         XPCWrappedNativeScope::FindInJSObjectScope(ccx, obj);
     548           94291 :     XPCContext *xpcc = scope->GetContext();
     549                 : 
     550           94291 :     if (xpcc) {
     551           94253 :         JSContext *cx = xpcc->GetJSContext();
     552           94253 :         JS_AbortIfWrongThread(JS_GetRuntime(cx));
     553           94253 :         return cx;
     554                 :     }
     555                 : 
     556              38 :     return nsnull;
     557                 : }
     558                 : 
     559                 : class SameOriginCheckedComponent : public nsISecurityCheckedComponent
     560               0 : {
     561                 : public:
     562               0 :     SameOriginCheckedComponent(nsXPCWrappedJS* delegate)
     563               0 :         : mDelegate(delegate)
     564               0 :     {}
     565                 : 
     566                 :     NS_DECL_ISUPPORTS
     567                 :     NS_DECL_NSISECURITYCHECKEDCOMPONENT
     568                 : 
     569                 : private:
     570                 :     nsRefPtr<nsXPCWrappedJS> mDelegate;
     571                 : };
     572                 : 
     573               0 : NS_IMPL_ADDREF(SameOriginCheckedComponent)
     574               0 : NS_IMPL_RELEASE(SameOriginCheckedComponent)
     575                 : 
     576               0 : NS_INTERFACE_MAP_BEGIN(SameOriginCheckedComponent)
     577               0 :     NS_INTERFACE_MAP_ENTRY(nsISecurityCheckedComponent)
     578               0 : NS_INTERFACE_MAP_END_AGGREGATED(mDelegate)
     579                 : 
     580                 : NS_IMETHODIMP
     581               0 : SameOriginCheckedComponent::CanCreateWrapper(const nsIID * iid,
     582                 :                                              char **_retval NS_OUTPARAM)
     583                 : {
     584                 :     // XXX This doesn't actually work because nsScriptSecurityManager doesn't
     585                 :     // know what to do with "sameOrigin" for canCreateWrapper.
     586               0 :     *_retval = NS_strdup("sameOrigin");
     587               0 :     return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     588                 : }
     589                 : 
     590                 : NS_IMETHODIMP
     591               0 : SameOriginCheckedComponent::CanCallMethod(const nsIID * iid,
     592                 :                                           const PRUnichar *methodName,
     593                 :                                           char **_retval NS_OUTPARAM)
     594                 : {
     595               0 :     *_retval = NS_strdup("sameOrigin");
     596               0 :     return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     597                 : }
     598                 : 
     599                 : NS_IMETHODIMP
     600               0 : SameOriginCheckedComponent::CanGetProperty(const nsIID * iid,
     601                 :                                            const PRUnichar *propertyName,
     602                 :                                            char **_retval NS_OUTPARAM)
     603                 : {
     604               0 :     *_retval = NS_strdup("sameOrigin");
     605               0 :     return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     606                 : }
     607                 : 
     608                 : NS_IMETHODIMP
     609               0 : SameOriginCheckedComponent::CanSetProperty(const nsIID * iid,
     610                 :                                            const PRUnichar *propertyName,
     611                 :                                            char **_retval NS_OUTPARAM)
     612                 : {
     613               0 :     *_retval = NS_strdup("sameOrigin");
     614               0 :     return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     615                 : }
     616                 : 
     617                 : NS_IMETHODIMP
     618          941967 : nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
     619                 :                                              REFNSIID aIID,
     620                 :                                              void** aInstancePtr)
     621                 : {
     622          941967 :     if (aIID.Equals(NS_GET_IID(nsIXPConnectJSObjectHolder))) {
     623               0 :         NS_ADDREF(self);
     624               0 :         *aInstancePtr = (void*) static_cast<nsIXPConnectJSObjectHolder*>(self);
     625               0 :         return NS_OK;
     626                 :     }
     627                 : 
     628                 :     // Objects internal to xpconnect are the only objects that even know *how*
     629                 :     // to ask for this iid. And none of them bother refcounting the thing.
     630          941967 :     if (aIID.Equals(NS_GET_IID(WrappedJSIdentity))) {
     631                 :         // asking to find out if this is a wrapper object
     632           17078 :         *aInstancePtr = WrappedJSIdentity::GetSingleton();
     633           17078 :         return NS_OK;
     634                 :     }
     635                 : 
     636          924889 :     if (aIID.Equals(NS_GET_IID(nsIPropertyBag))) {
     637                 :         // We only want to expose one implementation from our aggregate.
     638               7 :         nsXPCWrappedJS* root = self->GetRootWrapper();
     639                 : 
     640               7 :         if (!root->IsValid()) {
     641               0 :             *aInstancePtr = nsnull;
     642               0 :             return NS_NOINTERFACE;
     643                 :         }
     644                 : 
     645               7 :         NS_ADDREF(root);
     646               7 :         *aInstancePtr = (void*) static_cast<nsIPropertyBag*>(root);
     647               7 :         return NS_OK;
     648                 :     }
     649                 : 
     650                 :     // We can't have a cached wrapper.
     651          924882 :     if (aIID.Equals(NS_GET_IID(nsWrapperCache))) {
     652          300802 :         *aInstancePtr = nsnull;
     653          300802 :         return NS_NOINTERFACE;
     654                 :     }
     655                 : 
     656          624080 :     JSContext *context = GetContextFromObject(self->GetJSObject());
     657         1248160 :     XPCCallContext ccx(NATIVE_CALLER, context);
     658          624080 :     if (!ccx.IsValid()) {
     659               0 :         *aInstancePtr = nsnull;
     660               0 :         return NS_NOINTERFACE;
     661                 :     }
     662                 : 
     663                 :     // We support nsISupportsWeakReference iff the root wrapped JSObject
     664                 :     // claims to support it in its QueryInterface implementation.
     665          624080 :     if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) {
     666                 :         // We only want to expose one implementation from our aggregate.
     667            5160 :         nsXPCWrappedJS* root = self->GetRootWrapper();
     668                 : 
     669                 :         // Fail if JSObject doesn't claim support for nsISupportsWeakReference
     670           10320 :         if (!root->IsValid() ||
     671            5160 :             !CallQueryInterfaceOnJSObject(ccx, root->GetJSObject(), aIID)) {
     672               1 :             *aInstancePtr = nsnull;
     673               1 :             return NS_NOINTERFACE;
     674                 :         }
     675                 : 
     676            5159 :         NS_ADDREF(root);
     677            5159 :         *aInstancePtr = (void*) static_cast<nsISupportsWeakReference*>(root);
     678            5159 :         return NS_OK;
     679                 :     }
     680                 : 
     681                 :     nsXPCWrappedJS* sibling;
     682                 : 
     683                 :     // Checks for any existing wrapper explicitly constructed for this iid.
     684                 :     // This includes the current 'self' wrapper. This also deals with the
     685                 :     // nsISupports case (for which it returns mRoot).
     686          618920 :     if (nsnull != (sibling = self->Find(aIID))) {
     687          483276 :         NS_ADDREF(sibling);
     688          483276 :         *aInstancePtr = sibling->GetXPTCStub();
     689          483276 :         return NS_OK;
     690                 :     }
     691                 : 
     692                 :     // Check if asking for an interface from which one of our wrappers inherits.
     693          135644 :     if (nsnull != (sibling = self->FindInherited(aIID))) {
     694            2241 :         NS_ADDREF(sibling);
     695            2241 :         *aInstancePtr = sibling->GetXPTCStub();
     696            2241 :         return NS_OK;
     697                 :     }
     698                 : 
     699                 :     // else we do the more expensive stuff...
     700                 : 
     701                 :     // Before calling out, ensure that we're not about to claim to implement
     702                 :     // nsISecurityCheckedComponent for an untrusted object. Doing so causes
     703                 :     // problems. See bug 352882.
     704                 :     // But if this is a content object, then we might be wrapping it for
     705                 :     // content. If our JS object isn't a double-wrapped object (that is, we
     706                 :     // don't have XPCWrappedJS(XPCWrappedNative(some C++ object))), then it
     707                 :     // definitely will not have classinfo (and therefore won't be a DOM
     708                 :     // object). Since content wants to be able to use these objects (directly
     709                 :     // or indirectly, see bug 483672), we implement nsISecurityCheckedComponent
     710                 :     // for them and tell caps that they are also bound by the same origin
     711                 :     // model.
     712                 : 
     713          133403 :     if (aIID.Equals(NS_GET_IID(nsISecurityCheckedComponent))) {
     714                 :         // XXX This code checks to see if the given object has chrome (also
     715                 :         // known as system) principals. It really wants to do a
     716                 :         // UniversalXPConnect type check.
     717                 : 
     718            2170 :         *aInstancePtr = nsnull;
     719                 : 
     720            2170 :         if (!XPCPerThreadData::IsMainThread(ccx.GetJSContext()))
     721               0 :             return NS_NOINTERFACE;
     722                 : 
     723            2170 :         nsXPConnect *xpc = nsXPConnect::GetXPConnect();
     724                 :         nsCOMPtr<nsIScriptSecurityManager> secMan =
     725            4340 :             do_QueryInterface(xpc->GetDefaultSecurityManager());
     726            2170 :         if (!secMan)
     727               0 :             return NS_NOINTERFACE;
     728                 : 
     729            2170 :         JSObject *selfObj = self->GetJSObject();
     730            4340 :         nsCOMPtr<nsIPrincipal> objPrin;
     731            2170 :         nsresult rv = secMan->GetObjectPrincipal(ccx, selfObj,
     732            2170 :                                                  getter_AddRefs(objPrin));
     733            2170 :         if (NS_FAILED(rv))
     734               0 :             return rv;
     735                 : 
     736                 :         bool isSystem;
     737            2170 :         rv = secMan->IsSystemPrincipal(objPrin, &isSystem);
     738            2170 :         if ((NS_FAILED(rv) || !isSystem) &&
     739               0 :             !IS_WRAPPER_CLASS(js::GetObjectClass(selfObj))) {
     740                 :             // A content object.
     741                 :             nsRefPtr<SameOriginCheckedComponent> checked =
     742               0 :                 new SameOriginCheckedComponent(self);
     743               0 :             if (!checked)
     744               0 :                 return NS_ERROR_OUT_OF_MEMORY;
     745               0 :             *aInstancePtr = checked.forget().get();
     746               0 :             return NS_OK;
     747                 :         }
     748                 :     }
     749                 : 
     750                 :     // check if the JSObject claims to implement this interface
     751                 :     JSObject* jsobj = CallQueryInterfaceOnJSObject(ccx, self->GetJSObject(),
     752          133403 :                                                    aIID);
     753          133403 :     if (jsobj) {
     754                 :         // protect jsobj until it is actually attached
     755           12754 :         AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(jsobj));
     756                 : 
     757                 :         // We can't use XPConvert::JSObject2NativeInterface() here
     758                 :         // since that can find a XPCWrappedNative directly on the
     759                 :         // proto chain, and we don't want that here. We need to find
     760                 :         // the actual JS object that claimed it supports the interface
     761                 :         // we're looking for or we'll potentially bypass security
     762                 :         // checks etc by calling directly through to a native found on
     763                 :         // the prototype chain.
     764                 :         //
     765                 :         // Instead, simply do the nsXPCWrappedJS part of
     766                 :         // XPConvert::JSObject2NativeInterface() here to make sure we
     767                 :         // get a new (or used) nsXPCWrappedJS.
     768                 :         nsXPCWrappedJS* wrapper;
     769                 :         nsresult rv = nsXPCWrappedJS::GetNewOrUsed(ccx, jsobj, aIID, nsnull,
     770            6377 :                                                    &wrapper);
     771            6377 :         if (NS_SUCCEEDED(rv) && wrapper) {
     772                 :             // We need to go through the QueryInterface logic to make
     773                 :             // this return the right thing for the various 'special'
     774                 :             // interfaces; e.g.  nsIPropertyBag.
     775            6377 :             rv = wrapper->QueryInterface(aIID, aInstancePtr);
     776            6377 :             NS_RELEASE(wrapper);
     777            6377 :             return rv;
     778                 :         }
     779                 :     }
     780                 : 
     781                 :     // else...
     782                 :     // no can do
     783          127026 :     *aInstancePtr = nsnull;
     784          127026 :     return NS_NOINTERFACE;
     785                 : }
     786                 : 
     787                 : JSObject*
     788          156775 : nsXPCWrappedJSClass::GetRootJSObject(XPCCallContext& ccx, JSObject* aJSObj)
     789                 : {
     790                 :     JSObject* result = CallQueryInterfaceOnJSObject(ccx, aJSObj,
     791          156775 :                                                     NS_GET_IID(nsISupports));
     792          156775 :     if (!result)
     793           79579 :         return aJSObj;
     794           77196 :     JSObject* inner = XPCWrapper::Unwrap(ccx, result);
     795           77196 :     if (inner)
     796               0 :         return inner;
     797           77196 :     return result;
     798                 : }
     799                 : 
     800                 : void
     801               0 : xpcWrappedJSErrorReporter(JSContext *cx, const char *message,
     802                 :                           JSErrorReport *report)
     803                 : {
     804               0 :     if (report) {
     805                 :         // If it is an exception report, then we can just deal with the
     806                 :         // exception later (if not caught in the JS code).
     807               0 :         if (JSREPORT_IS_EXCEPTION(report->flags)) {
     808                 :             // XXX We have a problem with error reports from uncaught exceptions.
     809                 :             //
     810                 :             // http://bugzilla.mozilla.org/show_bug.cgi?id=66453
     811                 :             //
     812                 :             // The issue is...
     813                 :             //
     814                 :             // We can't assume that the exception will *stay* uncaught. So, if
     815                 :             // we build an nsIXPCException here and the underlying exception
     816                 :             // really is caught before our script is done running then we blow
     817                 :             // it by returning failure to our caller when the script didn't
     818                 :             // really fail. However, This report contains error location info
     819                 :             // that is no longer available after the script is done. So, if the
     820                 :             // exception really is not caught (and is a non-engine exception)
     821                 :             // then we've lost the oportunity to capture the script location
     822                 :             // info that we *could* have captured here.
     823                 :             //
     824                 :             // This is expecially an issue with nested evaluations.
     825                 :             //
     826                 :             // Perhaps we could capture an expception here and store it as
     827                 :             // 'provisional' and then later if there is a pending exception
     828                 :             // when the script is done then we could maybe compare that in some
     829                 :             // way with the 'provisional' one in which we captured location info.
     830                 :             // We would not want to assume that the one discovered here is the
     831                 :             // same one that is later detected. This could cause us to lie.
     832                 :             //
     833                 :             // The thing is. we do not currently store the right stuff to compare
     834                 :             // these two nsIXPCExceptions (triggered by the same exception jsval
     835                 :             // in the engine). Maybe we should store the jsval and compare that?
     836                 :             // Maybe without even rooting it since we will not dereference it.
     837                 :             // This is inexact, but maybe the right thing to do?
     838                 :             //
     839                 :             // if (report->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)) ...
     840                 :             //
     841                 : 
     842               0 :             return;
     843                 :         }
     844                 : 
     845               0 :         if (JSREPORT_IS_WARNING(report->flags)) {
     846                 :             // XXX printf the warning (#ifdef DEBUG only!).
     847                 :             // XXX send the warning to the console service.
     848               0 :             return;
     849                 :         }
     850                 :     }
     851                 : 
     852               0 :     XPCCallContext ccx(NATIVE_CALLER, cx);
     853               0 :     if (!ccx.IsValid())
     854                 :         return;
     855                 : 
     856               0 :     nsCOMPtr<nsIException> e;
     857                 :     XPCConvert::JSErrorToXPCException(ccx, message, nsnull, nsnull, report,
     858               0 :                                       getter_AddRefs(e));
     859               0 :     if (e)
     860               0 :         ccx.GetXPCContext()->SetException(e);
     861                 : }
     862                 : 
     863                 : JSBool
     864            1821 : nsXPCWrappedJSClass::GetArraySizeFromParam(JSContext* cx,
     865                 :                                            const XPTMethodDescriptor* method,
     866                 :                                            const nsXPTParamInfo& param,
     867                 :                                            uint16_t methodIndex,
     868                 :                                            uint8_t paramIndex,
     869                 :                                            nsXPTCMiniVariant* nativeParams,
     870                 :                                            uint32_t* result)
     871                 : {
     872                 :     uint8_t argnum;
     873                 :     nsresult rv;
     874                 : 
     875            1821 :     rv = mInfo->GetSizeIsArgNumberForParam(methodIndex, &param, 0, &argnum);
     876            1821 :     if (NS_FAILED(rv))
     877               0 :         return false;
     878                 : 
     879            1821 :     const nsXPTParamInfo& arg_param = method->params[argnum];
     880            1821 :     const nsXPTType& arg_type = arg_param.GetType();
     881                 : 
     882                 :     // This should be enforced by the xpidl compiler, but it's not.
     883                 :     // See bug 695235.
     884            1821 :     NS_ABORT_IF_FALSE(arg_type.TagPart() == nsXPTType::T_U32,
     885                 :                       "size_is references parameter of invalid type.");
     886                 : 
     887            1821 :     if (arg_param.IsIndirect())
     888            1733 :         *result = *(uint32_t*)nativeParams[argnum].val.p;
     889                 :     else
     890              88 :         *result = nativeParams[argnum].val.u32;
     891                 : 
     892            1821 :     return true;
     893                 : }
     894                 : 
     895                 : JSBool
     896          377406 : nsXPCWrappedJSClass::GetInterfaceTypeFromParam(JSContext* cx,
     897                 :                                                const XPTMethodDescriptor* method,
     898                 :                                                const nsXPTParamInfo& param,
     899                 :                                                uint16_t methodIndex,
     900                 :                                                const nsXPTType& type,
     901                 :                                                nsXPTCMiniVariant* nativeParams,
     902                 :                                                nsID* result)
     903                 : {
     904          377406 :     uint8_t type_tag = type.TagPart();
     905                 : 
     906          377406 :     if (type_tag == nsXPTType::T_INTERFACE) {
     907          367862 :         if (NS_SUCCEEDED(GetInterfaceInfo()->
     908                 :                          GetIIDForParamNoAlloc(methodIndex, &param, result))) {
     909          367862 :             return true;
     910                 :         }
     911            9544 :     } else if (type_tag == nsXPTType::T_INTERFACE_IS) {
     912                 :         uint8_t argnum;
     913                 :         nsresult rv;
     914                 :         rv = mInfo->GetInterfaceIsArgNumberForParam(methodIndex,
     915            9544 :                                                     &param, &argnum);
     916            9544 :         if (NS_FAILED(rv))
     917               0 :             return false;
     918                 : 
     919            9544 :         const nsXPTParamInfo& arg_param = method->params[argnum];
     920            9544 :         const nsXPTType& arg_type = arg_param.GetType();
     921                 : 
     922            9544 :         if (arg_type.TagPart() == nsXPTType::T_IID) {
     923            9544 :             if (arg_param.IsIndirect()) {
     924               6 :                 nsID** p = (nsID**) nativeParams[argnum].val.p;
     925               6 :                 if (!p || !*p)
     926               0 :                     return false;
     927               6 :                 *result = **p;
     928                 :             } else {
     929            9538 :                 nsID* p = (nsID*) nativeParams[argnum].val.p;
     930            9538 :                 if (!p)
     931               0 :                     return false;
     932            9538 :                 *result = *p;
     933                 :             }
     934            9544 :             return true;
     935                 :         }
     936                 :     }
     937               0 :     return false;
     938                 : }
     939                 : 
     940                 : void
     941               4 : nsXPCWrappedJSClass::CleanupPointerArray(const nsXPTType& datum_type,
     942                 :                                          uint32_t array_count,
     943                 :                                          void** arrayp)
     944                 : {
     945               4 :     if (datum_type.IsInterfacePointer()) {
     946               2 :         nsISupports** pp = (nsISupports**) arrayp;
     947              11 :         for (uint32_t k = 0; k < array_count; k++) {
     948               9 :             nsISupports* p = pp[k];
     949               9 :             NS_IF_RELEASE(p);
     950                 :         }
     951                 :     } else {
     952               2 :         void** pp = (void**) arrayp;
     953              16 :         for (uint32_t k = 0; k < array_count; k++) {
     954              14 :             void* p = pp[k];
     955              14 :             if (p) nsMemory::Free(p);
     956                 :         }
     957                 :     }
     958               4 : }
     959                 : 
     960                 : void
     961              34 : nsXPCWrappedJSClass::CleanupPointerTypeObject(const nsXPTType& type,
     962                 :                                               void** pp)
     963                 : {
     964              34 :     NS_ASSERTION(pp,"null pointer");
     965              34 :     if (type.IsInterfacePointer()) {
     966               2 :         nsISupports* p = *((nsISupports**)pp);
     967               2 :         if (p) p->Release();
     968                 :     } else {
     969              32 :         void* p = *((void**)pp);
     970              32 :         if (p) nsMemory::Free(p);
     971                 :     }
     972              34 : }
     973                 : 
     974                 : class AutoClearPendingException
     975                 : {
     976                 : public:
     977            6889 :   AutoClearPendingException(JSContext *cx) : mCx(cx) { }
     978            6889 :   ~AutoClearPendingException() { JS_ClearPendingException(mCx); }
     979                 : private:
     980                 :   JSContext* mCx;
     981                 : };
     982                 : 
     983                 : nsresult
     984            6889 : nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
     985                 :                                        const char * aPropertyName,
     986                 :                                        const char * anInterfaceName,
     987                 :                                        bool aForceReport)
     988                 : {
     989            6889 :     XPCContext * xpcc = ccx.GetXPCContext();
     990            6889 :     JSContext * cx = ccx.GetJSContext();
     991           13778 :     nsCOMPtr<nsIException> xpc_exception;
     992                 :     /* this one would be set by our error reporter */
     993                 : 
     994            6889 :     xpcc->GetException(getter_AddRefs(xpc_exception));
     995            6889 :     if (xpc_exception)
     996              88 :         xpcc->SetException(nsnull);
     997                 : 
     998                 :     // get this right away in case we do something below to cause JS code
     999                 :     // to run on this JSContext
    1000            6889 :     nsresult pending_result = xpcc->GetPendingResult();
    1001                 : 
    1002                 :     jsval js_exception;
    1003            6889 :     JSBool is_js_exception = JS_GetPendingException(cx, &js_exception);
    1004                 : 
    1005                 :     /* JS might throw an expection whether the reporter was called or not */
    1006            6889 :     if (is_js_exception) {
    1007            6801 :         if (!xpc_exception)
    1008                 :             XPCConvert::JSValToXPCException(ccx, js_exception, anInterfaceName,
    1009                 :                                             aPropertyName,
    1010            6801 :                                             getter_AddRefs(xpc_exception));
    1011                 : 
    1012                 :         /* cleanup and set failed even if we can't build an exception */
    1013            6801 :         if (!xpc_exception) {
    1014               0 :             ccx.GetThreadData()->SetException(nsnull); // XXX necessary?
    1015                 :         }
    1016                 :     }
    1017                 : 
    1018           13778 :     AutoClearPendingException acpe(cx);
    1019                 : 
    1020            6889 :     if (xpc_exception) {
    1021                 :         nsresult e_result;
    1022            6889 :         if (NS_SUCCEEDED(xpc_exception->GetResult(&e_result))) {
    1023                 :             // Figure out whether or not we should report this exception.
    1024            6889 :             bool reportable = xpc_IsReportableErrorCode(e_result);
    1025            6889 :             if (reportable) {
    1026                 :                 // Always want to report forced exceptions and XPConnect's own
    1027                 :                 // errors.
    1028                 :                 reportable = aForceReport ||
    1029            6888 :                     NS_ERROR_GET_MODULE(e_result) == NS_ERROR_MODULE_XPCONNECT;
    1030                 : 
    1031                 :                 // See if an environment variable was set or someone has told us
    1032                 :                 // that a user pref was set indicating that we should report all
    1033                 :                 // exceptions.
    1034            6888 :                 if (!reportable)
    1035            6434 :                     reportable = nsXPConnect::ReportAllJSExceptions();
    1036                 : 
    1037                 :                 // Finally, check to see if this is the last JS frame on the
    1038                 :                 // stack. If so then we always want to report it.
    1039            6888 :                 if (!reportable) {
    1040            6434 :                     bool onlyNativeStackFrames = true;
    1041            6434 :                     JSStackFrame * fp = nsnull;
    1042           12868 :                     while ((fp = JS_FrameIterator(cx, &fp))) {
    1043            2082 :                         if (JS_IsScriptFrame(cx, fp)) {
    1044            2082 :                             onlyNativeStackFrames = false;
    1045            2082 :                             break;
    1046                 :                         }
    1047                 :                     }
    1048            6434 :                     reportable = onlyNativeStackFrames;
    1049                 :                 }
    1050                 : 
    1051                 :                 // Ugly special case for GetInterface. It's "special" in the
    1052                 :                 // same way as QueryInterface in that a failure is not
    1053                 :                 // exceptional and shouldn't be reported. We have to do this
    1054                 :                 // check here instead of in xpcwrappedjs (like we do for QI) to
    1055                 :                 // avoid adding extra code to all xpcwrappedjs objects.
    1056           14991 :                 if (reportable && e_result == NS_ERROR_NO_INTERFACE &&
    1057            4052 :                     !strcmp(anInterfaceName, "nsIInterfaceRequestor") &&
    1058            4051 :                     !strcmp(aPropertyName, "getInterface")) {
    1059            4051 :                     reportable = false;
    1060                 :                 }
    1061                 :             }
    1062                 : 
    1063                 :             // Try to use the error reporter set on the context to handle this
    1064                 :             // error if it came from a JS exception.
    1065            7556 :             if (reportable && is_js_exception &&
    1066             667 :                 JS_GetErrorReporter(cx) != xpcWrappedJSErrorReporter) {
    1067             667 :                 reportable = !JS_ReportPendingException(cx);
    1068                 :             }
    1069                 : 
    1070            6889 :             if (reportable) {
    1071                 : #ifdef DEBUG
    1072                 :                 static const char line[] =
    1073                 :                     "************************************************************\n";
    1074                 :                 static const char preamble[] =
    1075                 :                     "* Call to xpconnect wrapped JSObject produced this error:  *\n";
    1076                 :                 static const char cant_get_text[] =
    1077                 :                     "FAILED TO GET TEXT FROM EXCEPTION\n";
    1078                 : 
    1079              88 :                 fputs(line, stdout);
    1080              88 :                 fputs(preamble, stdout);
    1081                 :                 char* text;
    1082              88 :                 if (NS_SUCCEEDED(xpc_exception->ToString(&text)) && text) {
    1083              88 :                     fputs(text, stdout);
    1084              88 :                     fputs("\n", stdout);
    1085              88 :                     nsMemory::Free(text);
    1086                 :                 } else
    1087               0 :                     fputs(cant_get_text, stdout);
    1088              88 :                 fputs(line, stdout);
    1089                 : #endif
    1090                 : 
    1091                 :                 // Log the exception to the JS Console, so that users can do
    1092                 :                 // something with it.
    1093                 :                 nsCOMPtr<nsIConsoleService> consoleService
    1094             176 :                     (do_GetService(XPC_CONSOLE_CONTRACTID));
    1095              88 :                 if (nsnull != consoleService) {
    1096                 :                     nsresult rv;
    1097             176 :                     nsCOMPtr<nsIScriptError> scriptError;
    1098             176 :                     nsCOMPtr<nsISupports> errorData;
    1099              88 :                     rv = xpc_exception->GetData(getter_AddRefs(errorData));
    1100              88 :                     if (NS_SUCCEEDED(rv))
    1101              88 :                         scriptError = do_QueryInterface(errorData);
    1102                 : 
    1103              88 :                     if (nsnull == scriptError) {
    1104                 :                         // No luck getting one from the exception, so
    1105                 :                         // try to cook one up.
    1106              88 :                         scriptError = do_CreateInstance(XPC_SCRIPT_ERROR_CONTRACTID);
    1107              88 :                         if (nsnull != scriptError) {
    1108                 :                             char* exn_string;
    1109              88 :                             rv = xpc_exception->ToString(&exn_string);
    1110              88 :                             if (NS_SUCCEEDED(rv)) {
    1111                 :                                 // use toString on the exception as the message
    1112             176 :                                 nsAutoString newMessage;
    1113              88 :                                 newMessage.AssignWithConversion(exn_string);
    1114              88 :                                 nsMemory::Free((void *) exn_string);
    1115                 : 
    1116                 :                                 // try to get filename, lineno from the first
    1117                 :                                 // stack frame location.
    1118              88 :                                 PRInt32 lineNumber = 0;
    1119             176 :                                 nsXPIDLCString sourceName;
    1120                 : 
    1121             176 :                                 nsCOMPtr<nsIStackFrame> location;
    1122              88 :                                 xpc_exception->
    1123              88 :                                     GetLocation(getter_AddRefs(location));
    1124              88 :                                 if (location) {
    1125                 :                                     // Get line number w/o checking; 0 is ok.
    1126              16 :                                     location->GetLineNumber(&lineNumber);
    1127                 : 
    1128                 :                                     // get a filename.
    1129              16 :                                     rv = location->GetFilename(getter_Copies(sourceName));
    1130                 :                                 }
    1131                 : 
    1132              88 :                                 rv = scriptError->InitWithWindowID(newMessage.get(),
    1133              88 :                                                                    NS_ConvertASCIItoUTF16(sourceName).get(),
    1134                 :                                                                    nsnull,
    1135                 :                                                                    lineNumber, 0, 0,
    1136                 :                                                                    "XPConnect JavaScript",
    1137              88 :                                                                    nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
    1138              88 :                                 if (NS_FAILED(rv))
    1139               0 :                                     scriptError = nsnull;
    1140                 :                             }
    1141                 :                         }
    1142                 :                     }
    1143              88 :                     if (nsnull != scriptError)
    1144              88 :                         consoleService->LogMessage(scriptError);
    1145                 :                 }
    1146                 :             }
    1147                 :             // Whether or not it passes the 'reportable' test, it might
    1148                 :             // still be an error and we have to do the right thing here...
    1149            6889 :             if (NS_FAILED(e_result)) {
    1150            6888 :                 ccx.GetThreadData()->SetException(xpc_exception);
    1151            6888 :                 return e_result;
    1152                 :             }
    1153                 :         }
    1154                 :     } else {
    1155                 :         // see if JS code signaled failure result without throwing exception
    1156               0 :         if (NS_FAILED(pending_result)) {
    1157               0 :             return pending_result;
    1158                 :         }
    1159                 :     }
    1160               1 :     return NS_ERROR_FAILURE;
    1161                 : }
    1162                 : 
    1163                 : class ContextPrincipalGuard
    1164                 : {
    1165                 :     nsIScriptSecurityManager *ssm;
    1166                 :     XPCCallContext &ccx;
    1167                 :   public:
    1168         1225564 :     ContextPrincipalGuard(XPCCallContext &ccx)
    1169         1225564 :       : ssm(nsnull), ccx(ccx) {}
    1170         1225564 :     void principalPushed(nsIScriptSecurityManager *ssm) { this->ssm = ssm; }
    1171         1225564 :     ~ContextPrincipalGuard() { if (ssm) ssm->PopContextPrincipal(ccx); }
    1172                 : };
    1173                 : 
    1174                 : NS_IMETHODIMP
    1175         1225569 : nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
    1176                 :                                 const XPTMethodDescriptor* info,
    1177                 :                                 nsXPTCMiniVariant* nativeParams)
    1178                 : {
    1179         1225569 :     jsval* sp = nsnull;
    1180         1225569 :     jsval* argv = nsnull;
    1181                 :     uint8_t i;
    1182         1225569 :     nsresult retval = NS_ERROR_FAILURE;
    1183         1225569 :     nsresult pending_result = NS_OK;
    1184                 :     JSBool success;
    1185         1225569 :     JSBool readyToDoTheCall = false;
    1186                 :     nsID  param_iid;
    1187         1225569 :     const char* name = info->name;
    1188                 :     jsval fval;
    1189                 :     JSBool foundDependentParam;
    1190                 : 
    1191                 :     // Make sure not to set the callee on ccx until after we've gone through
    1192                 :     // the whole nsIXPCFunctionThisTranslator bit.  That code uses ccx to
    1193                 :     // convert natives to JSObjects, but we do NOT plan to pass those JSObjects
    1194                 :     // to our real callee.
    1195         1225569 :     JSContext *context = GetContextFromObject(wrapper->GetJSObject());
    1196         2451138 :     XPCCallContext ccx(NATIVE_CALLER, context);
    1197         1225569 :     if (!ccx.IsValid())
    1198               0 :         return retval;
    1199                 : 
    1200         1225569 :     XPCContext *xpcc = ccx.GetXPCContext();
    1201         1225569 :     JSContext *cx = ccx.GetJSContext();
    1202                 : 
    1203         1225569 :     if (!cx || !xpcc || !IsReflectable(methodIndex))
    1204               5 :         return NS_ERROR_FAILURE;
    1205                 : 
    1206         1225564 :     JSObject *obj = wrapper->GetJSObject();
    1207         1225564 :     JSObject *thisObj = obj;
    1208                 : 
    1209         2451128 :     JSAutoEnterCompartment ac;
    1210         1225564 :     if (!ac.enter(cx, obj))
    1211               0 :         return NS_ERROR_FAILURE;
    1212                 : 
    1213         1225564 :     ccx.SetScopeForNewJSObjects(obj);
    1214                 : 
    1215         2451128 :     JS::AutoValueVector args(cx);
    1216         2451128 :     AutoScriptEvaluate scriptEval(cx);
    1217         2451128 :     ContextPrincipalGuard principalGuard(ccx);
    1218                 : 
    1219                 :     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
    1220         1225564 :     uint8_t paramCount = info->num_args;
    1221                 :     uint8_t argc = paramCount -
    1222         1225564 :         (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
    1223                 : 
    1224         1225564 :     if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter))
    1225               0 :         goto pre_call_clean_up;
    1226                 : 
    1227         1225564 :     xpcc->SetPendingResult(pending_result);
    1228         1225564 :     xpcc->SetException(nsnull);
    1229         1225564 :     ccx.GetThreadData()->SetException(nsnull);
    1230                 : 
    1231         1225564 :     if (XPCPerThreadData::IsMainThread(ccx)) {
    1232                 :         // TODO Remove me in favor of security wrappers.
    1233         1225564 :         nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
    1234         1225564 :         if (ssm) {
    1235                 :             nsIPrincipal *objPrincipal =
    1236         1225564 :                 xpc::AccessCheck::getPrincipal(js::GetObjectCompartment(obj));
    1237         1225564 :             if (objPrincipal) {
    1238         1225564 :                 JSStackFrame* fp = nsnull;
    1239                 :                 nsresult rv =
    1240                 :                     ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp),
    1241         1225564 :                                               objPrincipal);
    1242         1225564 :                 if (NS_FAILED(rv)) {
    1243               0 :                     JS_ReportOutOfMemory(ccx);
    1244               0 :                     retval = NS_ERROR_OUT_OF_MEMORY;
    1245               0 :                     goto pre_call_clean_up;
    1246                 :                 }
    1247                 : 
    1248         1225564 :                 principalGuard.principalPushed(ssm);
    1249                 :             }
    1250                 :         }
    1251                 :     }
    1252                 : 
    1253                 :     // We use js_Invoke so that the gcthings we use as args will be rooted by
    1254                 :     // the engine as we do conversions and prepare to do the function call.
    1255                 : 
    1256                 :     // setup stack
    1257                 : 
    1258                 :     // if this isn't a function call then we don't need to push extra stuff
    1259         1225564 :     if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) {
    1260                 :         // We get fval before allocating the stack to avoid gc badness that can
    1261                 :         // happen if the GetProperty call leaves our request and the gc runs
    1262                 :         // while the stack we allocate contains garbage.
    1263                 : 
    1264                 :         // If the interface is marked as a [function] then we will assume that
    1265                 :         // our JSObject is a function and not an object with a named method.
    1266                 : 
    1267                 :         bool isFunction;
    1268          441283 :         if (NS_FAILED(mInfo->IsFunction(&isFunction)))
    1269               0 :             goto pre_call_clean_up;
    1270                 : 
    1271                 :         // In the xpidl [function] case we are making sure now that the
    1272                 :         // JSObject is callable. If it is *not* callable then we silently
    1273                 :         // fallback to looking up the named property...
    1274                 :         // (because jst says he thinks this fallback is 'The Right Thing'.)
    1275                 :         //
    1276                 :         // In the normal (non-function) case we just lookup the property by
    1277                 :         // name and as long as the object has such a named property we go ahead
    1278                 :         // and try to make the call. If it turns out the named property is not
    1279                 :         // a callable object then the JS engine will throw an error and we'll
    1280                 :         // pass this along to the caller as an exception/result code.
    1281                 : 
    1282          499466 :         if (isFunction &&
    1283           58183 :             JS_TypeOfValue(ccx, OBJECT_TO_JSVAL(obj)) == JSTYPE_FUNCTION) {
    1284           11962 :             fval = OBJECT_TO_JSVAL(obj);
    1285                 : 
    1286                 :             // We may need to translate the 'this' for the function object.
    1287                 : 
    1288           11962 :             if (paramCount) {
    1289           10315 :                 const nsXPTParamInfo& firstParam = info->params[0];
    1290           10315 :                 if (firstParam.IsIn()) {
    1291           10315 :                     const nsXPTType& firstType = firstParam.GetType();
    1292                 : 
    1293           10315 :                     if (firstType.IsInterfacePointer()) {
    1294                 :                         nsIXPCFunctionThisTranslator* translator;
    1295                 : 
    1296                 :                         IID2ThisTranslatorMap* map =
    1297            7466 :                             mRuntime->GetThisTranslatorMap();
    1298                 : 
    1299                 :                         {
    1300           14932 :                             XPCAutoLock lock(mRuntime->GetMapLock()); // scoped lock
    1301            7466 :                             translator = map->Find(mIID);
    1302                 :                         }
    1303                 : 
    1304            7466 :                         if (translator) {
    1305            3965 :                             bool hideFirstParamFromJS = false;
    1306            3965 :                             nsIID* newWrapperIID = nsnull;
    1307            7930 :                             nsCOMPtr<nsISupports> newThis;
    1308                 : 
    1309            3965 :                             if (NS_FAILED(translator->
    1310                 :                                           TranslateThis((nsISupports*)nativeParams[0].val.p,
    1311                 :                                                         mInfo, methodIndex,
    1312                 :                                                         &hideFirstParamFromJS,
    1313                 :                                                         &newWrapperIID,
    1314                 :                                                         getter_AddRefs(newThis)))) {
    1315                 :                                 goto pre_call_clean_up;
    1316                 :                             }
    1317            3965 :                             if (hideFirstParamFromJS) {
    1318               0 :                                 NS_ERROR("HideFirstParamFromJS not supported");
    1319                 :                                 goto pre_call_clean_up;
    1320                 :                             }
    1321            3965 :                             if (newThis) {
    1322                 :                                 jsval v;
    1323            7930 :                                 xpcObjectHelper helper(newThis);
    1324                 :                                 JSBool ok =
    1325                 :                                   XPCConvert::NativeInterface2JSObject(ccx,
    1326                 :                                                                        &v, nsnull, helper, newWrapperIID,
    1327            3965 :                                                                        nsnull, false, nsnull);
    1328            3965 :                                 if (newWrapperIID)
    1329               0 :                                     nsMemory::Free(newWrapperIID);
    1330            3965 :                                 if (!ok) {
    1331                 :                                     goto pre_call_clean_up;
    1332                 :                                 }
    1333            3965 :                                 thisObj = JSVAL_TO_OBJECT(v);
    1334            3965 :                                 if (!JS_WrapObject(cx, &thisObj))
    1335                 :                                     goto pre_call_clean_up;
    1336                 :                             }
    1337                 :                         }
    1338                 :                     }
    1339                 :                 }
    1340                 :             }
    1341          429321 :         } else if (!JS_GetMethod(cx, obj, name, &thisObj, &fval)) {
    1342                 :             // XXX We really want to factor out the error reporting better and
    1343                 :             // specifically report the failure to find a function with this name.
    1344                 :             // This is what we do below if the property is found but is not a
    1345                 :             // function. We just need to factor better so we can get to that
    1346                 :             // reporting path from here.
    1347               0 :             goto pre_call_clean_up;
    1348                 :         }
    1349                 :     }
    1350                 : 
    1351         1225564 :     if (!args.resize(argc)) {
    1352               0 :         retval = NS_ERROR_OUT_OF_MEMORY;
    1353               0 :         goto pre_call_clean_up;
    1354                 :     }
    1355                 : 
    1356         1225564 :     argv = args.begin();
    1357         1225564 :     sp = argv;
    1358                 : 
    1359                 :     // build the args
    1360                 :     // NB: This assignment *looks* wrong because we haven't yet called our
    1361                 :     // function. However, we *have* already entered the compartmen that we're
    1362                 :     // about to call, and that's the global that we want here. In other words:
    1363                 :     // we're trusting the JS engine to come up with a good global to use for
    1364                 :     // our object (whatever it was).
    1365         1915856 :     for (i = 0; i < argc; i++) {
    1366          690292 :         const nsXPTParamInfo& param = info->params[i];
    1367          690292 :         const nsXPTType& type = param.GetType();
    1368          690292 :         nsXPTType datum_type;
    1369                 :         uint32_t array_count;
    1370          690292 :         bool isArray = type.IsArray();
    1371          690292 :         jsval val = JSVAL_NULL;
    1372         1380584 :         AUTO_MARK_JSVAL(ccx, &val);
    1373                 :         bool isSizedString = isArray ?
    1374                 :                 false :
    1375          690198 :                 type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
    1376         1380490 :                 type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
    1377                 : 
    1378                 : 
    1379                 :         // verify that null was not passed for 'out' param
    1380          690292 :         if (param.IsOut() && !nativeParams[i].val.p) {
    1381               0 :             retval = NS_ERROR_INVALID_ARG;
    1382                 :             goto pre_call_clean_up;
    1383                 :         }
    1384                 : 
    1385          690292 :         if (isArray) {
    1386              94 :             if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
    1387                 :                                                  &datum_type)))
    1388                 :                 goto pre_call_clean_up;
    1389                 :         } else
    1390          690198 :             datum_type = type;
    1391                 : 
    1392          690292 :         if (param.IsIn()) {
    1393                 :             nsXPTCMiniVariant* pv;
    1394                 : 
    1395          682119 :             if (param.IsIndirect())
    1396             187 :                 pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
    1397                 :             else
    1398          681932 :                 pv = &nativeParams[i];
    1399                 : 
    1400         1048790 :             if (datum_type.IsInterfacePointer() &&
    1401                 :                 !GetInterfaceTypeFromParam(cx, info, param, methodIndex,
    1402                 :                                            datum_type, nativeParams,
    1403          366671 :                                            &param_iid))
    1404                 :                 goto pre_call_clean_up;
    1405                 : 
    1406          682119 :             if (isArray || isSizedString) {
    1407              98 :                 if (!GetArraySizeFromParam(cx, info, param, methodIndex,
    1408              98 :                                            i, nativeParams, &array_count))
    1409                 :                     goto pre_call_clean_up;
    1410                 :             }
    1411                 : 
    1412          682119 :             if (isArray) {
    1413             188 :                 XPCLazyCallContext lccx(ccx);
    1414              94 :                 if (!XPCConvert::NativeArray2JS(lccx, &val,
    1415                 :                                                 (const void**)&pv->val,
    1416                 :                                                 datum_type, &param_iid,
    1417              94 :                                                 array_count, nsnull))
    1418                 :                     goto pre_call_clean_up;
    1419          682025 :             } else if (isSizedString) {
    1420               4 :                 if (!XPCConvert::NativeStringWithSize2JS(ccx, &val,
    1421                 :                                                          (const void*)&pv->val,
    1422                 :                                                          datum_type,
    1423               4 :                                                          array_count, nsnull))
    1424                 :                     goto pre_call_clean_up;
    1425                 :             } else {
    1426          682021 :                 if (!XPCConvert::NativeData2JS(ccx, &val, &pv->val, type,
    1427          682021 :                                                &param_iid, nsnull))
    1428                 :                     goto pre_call_clean_up;
    1429                 :             }
    1430                 :         }
    1431                 : 
    1432          690292 :         if (param.IsOut() || param.IsDipper()) {
    1433                 :             // create an 'out' object
    1434            8246 :             JSObject* out_obj = NewOutObject(cx, obj);
    1435            8246 :             if (!out_obj) {
    1436               0 :                 retval = NS_ERROR_OUT_OF_MEMORY;
    1437                 :                 goto pre_call_clean_up;
    1438                 :             }
    1439                 : 
    1440            8246 :             if (param.IsIn()) {
    1441              73 :                 if (!JS_SetPropertyById(cx, out_obj,
    1442              73 :                                         mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
    1443              73 :                                         &val)) {
    1444                 :                     goto pre_call_clean_up;
    1445                 :                 }
    1446                 :             }
    1447            8246 :             *sp++ = OBJECT_TO_JSVAL(out_obj);
    1448                 :         } else
    1449          682046 :             *sp++ = val;
    1450                 :     }
    1451                 : 
    1452         1225564 :     readyToDoTheCall = true;
    1453                 : 
    1454                 : pre_call_clean_up:
    1455                 :     // clean up any 'out' params handed in
    1456         2963861 :     for (i = 0; i < paramCount; i++) {
    1457         1738297 :         const nsXPTParamInfo& param = info->params[i];
    1458         1738297 :         if (!param.IsOut())
    1459         1423283 :             continue;
    1460                 : 
    1461          315014 :         const nsXPTType& type = param.GetType();
    1462          315014 :         if (!type.deprecated_IsPointer())
    1463          286902 :             continue;
    1464                 :         void* p;
    1465           28112 :         if (!(p = nativeParams[i].val.p))
    1466               0 :             continue;
    1467                 : 
    1468           28112 :         if (param.IsIn()) {
    1469              42 :             if (type.IsArray()) {
    1470                 :                 void** pp;
    1471               8 :                 if (nsnull != (pp = *((void***)p))) {
    1472                 : 
    1473                 :                     // we need to get the array length and iterate the items
    1474                 :                     uint32_t array_count;
    1475               8 :                     nsXPTType datum_type;
    1476                 : 
    1477              20 :                     if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
    1478                 :                                                             1, &datum_type)) &&
    1479               8 :                         datum_type.deprecated_IsPointer() &&
    1480                 :                         GetArraySizeFromParam(cx, info, param, methodIndex,
    1481               4 :                                               i, nativeParams, &array_count) &&
    1482                 :                         array_count) {
    1483                 : 
    1484               4 :                         CleanupPointerArray(datum_type, array_count, pp);
    1485                 :                     }
    1486                 : 
    1487                 :                     // always release the array if it is inout
    1488               8 :                     nsMemory::Free(pp);
    1489                 :                 }
    1490                 :             } else
    1491              34 :                 CleanupPointerTypeObject(type, (void**)p);
    1492                 :         }
    1493           28112 :         *((void**)p) = nsnull;
    1494                 :     }
    1495                 : 
    1496                 :     // Make sure "this" doesn't get deleted during this call.
    1497         2451128 :     nsCOMPtr<nsIXPCWrappedJSClass> kungFuDeathGrip(this);
    1498                 : 
    1499         1225564 :     if (!readyToDoTheCall)
    1500               0 :         return retval;
    1501                 : 
    1502                 :     // do the deed - note exceptions
    1503                 : 
    1504         1225564 :     JS_ClearPendingException(cx);
    1505                 : 
    1506                 :     jsval rval;
    1507         1225564 :     if (XPT_MD_IS_GETTER(info->flags)) {
    1508          758452 :         success = JS_GetProperty(cx, obj, name, argv);
    1509          758452 :         rval = *argv;
    1510          467112 :     } else if (XPT_MD_IS_SETTER(info->flags)) {
    1511           25829 :         success = JS_SetProperty(cx, obj, name, argv);
    1512           25829 :         rval = *argv;
    1513                 :     } else {
    1514          441283 :         if (!JSVAL_IS_PRIMITIVE(fval)) {
    1515          441195 :             uint32_t oldOpts = JS_GetOptions(cx);
    1516          441195 :             JS_SetOptions(cx, oldOpts | JSOPTION_DONT_REPORT_UNCAUGHT);
    1517                 : 
    1518          441195 :             success = JS_CallFunctionValue(cx, thisObj, fval, argc, argv, &rval);
    1519                 : 
    1520          441195 :             JS_SetOptions(cx, oldOpts);
    1521                 :         } else {
    1522                 :             // The property was not an object so can't be a function.
    1523                 :             // Let's build and 'throw' an exception.
    1524                 : 
    1525                 :             static const nsresult code =
    1526                 :                     NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
    1527                 :             static const char format[] = "%s \"%s\"";
    1528                 :             const char * msg;
    1529              88 :             char* sz = nsnull;
    1530                 : 
    1531              88 :             if (nsXPCException::NameAndFormatForNSResult(code, nsnull, &msg) && msg)
    1532              88 :                 sz = JS_smprintf(format, msg, name);
    1533                 : 
    1534             176 :             nsCOMPtr<nsIException> e;
    1535                 : 
    1536                 :             XPCConvert::ConstructException(code, sz, GetInterfaceName(), name,
    1537              88 :                                            nsnull, getter_AddRefs(e), nsnull, nsnull);
    1538              88 :             xpcc->SetException(e);
    1539              88 :             if (sz)
    1540              88 :                 JS_smprintf_free(sz);
    1541              88 :             success = false;
    1542                 :         }
    1543                 :     }
    1544                 : 
    1545         1225564 :     if (!success) {
    1546                 :         bool forceReport;
    1547            6889 :         if (NS_FAILED(mInfo->IsFunction(&forceReport)))
    1548               0 :             forceReport = false;
    1549                 : 
    1550                 :         // May also want to check if we're moving from content->chrome and force
    1551                 :         // a report in that case.
    1552                 : 
    1553            6889 :         return CheckForException(ccx, name, GetInterfaceName(), forceReport);
    1554                 :     }
    1555                 : 
    1556         1218675 :     ccx.GetThreadData()->SetException(nsnull); // XXX necessary?
    1557                 : 
    1558                 :     // convert out args and result
    1559                 :     // NOTE: this is the total number of native params, not just the args
    1560                 :     // Convert independent params only.
    1561                 :     // When we later convert the dependent params (if any) we will know that
    1562                 :     // the params upon which they depend will have already been converted -
    1563                 :     // regardless of ordering.
    1564                 : 
    1565         1218675 :     foundDependentParam = false;
    1566         2941699 :     for (i = 0; i < paramCount; i++) {
    1567         1723024 :         const nsXPTParamInfo& param = info->params[i];
    1568         1723024 :         NS_ABORT_IF_FALSE(!param.IsShared(), "[shared] implies [noscript]!");
    1569         1723024 :         if (!param.IsOut() && !param.IsDipper())
    1570          674512 :             continue;
    1571                 : 
    1572         1048512 :         const nsXPTType& type = param.GetType();
    1573         1048512 :         if (type.IsDependent()) {
    1574           11257 :             foundDependentParam = true;
    1575           11257 :             continue;
    1576                 :         }
    1577                 : 
    1578                 :         jsval val;
    1579         1037255 :         uint8_t type_tag = type.TagPart();
    1580                 :         nsXPTCMiniVariant* pv;
    1581                 : 
    1582         1037255 :         if (param.IsDipper())
    1583          741169 :             pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p;
    1584                 :         else
    1585          296086 :             pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
    1586                 : 
    1587         1037255 :         if (param.IsRetval())
    1588         1030341 :             val = rval;
    1589           13828 :         else if (JSVAL_IS_PRIMITIVE(argv[i]) ||
    1590            6914 :                  !JS_GetPropertyById(cx, JSVAL_TO_OBJECT(argv[i]),
    1591            6914 :                                      mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
    1592           13828 :                                      &val))
    1593               0 :             break;
    1594                 : 
    1595                 :         // setup allocator and/or iid
    1596                 : 
    1597         1037255 :         if (type_tag == nsXPTType::T_INTERFACE) {
    1598           10431 :             if (NS_FAILED(GetInterfaceInfo()->
    1599                 :                           GetIIDForParamNoAlloc(methodIndex, &param,
    1600                 :                                                 &param_iid)))
    1601               0 :                 break;
    1602                 :         }
    1603                 : 
    1604         1037255 :         if (!XPCConvert::JSData2Native(ccx, &pv->val, val, type,
    1605         1037255 :                                        !param.IsDipper(), &param_iid, nsnull))
    1606               0 :             break;
    1607                 :     }
    1608                 : 
    1609                 :     // if any params were dependent, then we must iterate again to convert them.
    1610         1218675 :     if (foundDependentParam && i == paramCount) {
    1611           45388 :         for (i = 0; i < paramCount; i++) {
    1612           34142 :             const nsXPTParamInfo& param = info->params[i];
    1613           34142 :             if (!param.IsOut())
    1614           21162 :                 continue;
    1615                 : 
    1616           12980 :             const nsXPTType& type = param.GetType();
    1617           12980 :             if (!type.IsDependent())
    1618            1723 :                 continue;
    1619                 : 
    1620                 :             jsval val;
    1621                 :             nsXPTCMiniVariant* pv;
    1622           11257 :             nsXPTType datum_type;
    1623                 :             uint32_t array_count;
    1624           11257 :             bool isArray = type.IsArray();
    1625                 :             bool isSizedString = isArray ?
    1626                 :                     false :
    1627            9542 :                     type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
    1628           20799 :                     type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
    1629                 : 
    1630           11257 :             pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
    1631                 : 
    1632           11257 :             if (param.IsRetval())
    1633           11246 :                 val = rval;
    1634              22 :             else if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(argv[i]),
    1635              11 :                                          mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
    1636              22 :                                          &val))
    1637               0 :                 break;
    1638                 : 
    1639                 :             // setup allocator and/or iid
    1640                 : 
    1641           11257 :             if (isArray) {
    1642            1715 :                 if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
    1643                 :                                                      &datum_type)))
    1644               0 :                     break;
    1645                 :             } else
    1646            9542 :                 datum_type = type;
    1647                 : 
    1648           11257 :             if (datum_type.IsInterfacePointer()) {
    1649           10735 :                if (!GetInterfaceTypeFromParam(cx, info, param, methodIndex,
    1650                 :                                               datum_type, nativeParams,
    1651           10735 :                                               &param_iid))
    1652               0 :                    break;
    1653                 :             }
    1654                 : 
    1655           11257 :             if (isArray || isSizedString) {
    1656            1719 :                 if (!GetArraySizeFromParam(cx, info, param, methodIndex,
    1657            1719 :                                            i, nativeParams, &array_count))
    1658               0 :                     break;
    1659                 :             }
    1660                 : 
    1661           11257 :             if (isArray) {
    1662            2178 :                 if (array_count &&
    1663                 :                     !XPCConvert::JSArray2Native(ccx, (void**)&pv->val, val,
    1664                 :                                                 array_count, datum_type,
    1665             463 :                                                 &param_iid, nsnull))
    1666               0 :                     break;
    1667            9542 :             } else if (isSizedString) {
    1668               4 :                 if (!XPCConvert::JSStringWithSize2Native(ccx,
    1669                 :                                                          (void*)&pv->val, val,
    1670                 :                                                          array_count, datum_type,
    1671               4 :                                                          nsnull))
    1672               0 :                     break;
    1673                 :             } else {
    1674            9538 :                 if (!XPCConvert::JSData2Native(ccx, &pv->val, val, type,
    1675                 :                                                true, &param_iid,
    1676            9538 :                                                nsnull))
    1677               0 :                     break;
    1678                 :             }
    1679                 :         }
    1680                 :     }
    1681                 : 
    1682         1218675 :     if (i != paramCount) {
    1683                 :         // We didn't manage all the result conversions!
    1684                 :         // We have to cleanup any junk that *did* get converted.
    1685                 : 
    1686               0 :         for (uint8_t k = 0; k < i; k++) {
    1687               0 :             const nsXPTParamInfo& param = info->params[k];
    1688               0 :             if (!param.IsOut())
    1689               0 :                 continue;
    1690               0 :             const nsXPTType& type = param.GetType();
    1691               0 :             if (!type.deprecated_IsPointer())
    1692               0 :                 continue;
    1693                 :             void* p;
    1694               0 :             if (!(p = nativeParams[k].val.p))
    1695               0 :                 continue;
    1696                 : 
    1697               0 :             if (type.IsArray()) {
    1698                 :                 void** pp;
    1699               0 :                 if (nsnull != (pp = *((void***)p))) {
    1700                 :                     // we need to get the array length and iterate the items
    1701                 :                     uint32_t array_count;
    1702               0 :                     nsXPTType datum_type;
    1703                 : 
    1704               0 :                     if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
    1705                 :                                                             1, &datum_type)) &&
    1706               0 :                         datum_type.deprecated_IsPointer() &&
    1707                 :                         GetArraySizeFromParam(cx, info, param, methodIndex,
    1708               0 :                                               k, nativeParams, &array_count) &&
    1709                 :                         array_count) {
    1710                 : 
    1711               0 :                         CleanupPointerArray(datum_type, array_count, pp);
    1712                 :                     }
    1713               0 :                     nsMemory::Free(pp);
    1714                 :                 }
    1715                 :             } else
    1716               0 :                 CleanupPointerTypeObject(type, (void**)p);
    1717               0 :             *((void**)p) = nsnull;
    1718                 :         }
    1719                 :     } else {
    1720                 :         // set to whatever the JS code might have set as the result
    1721         1218675 :         retval = pending_result;
    1722                 :     }
    1723                 : 
    1724         1218675 :     return retval;
    1725                 : }
    1726                 : 
    1727                 : const char*
    1728            6978 : nsXPCWrappedJSClass::GetInterfaceName()
    1729                 : {
    1730            6978 :     if (!mName)
    1731            2032 :         mInfo->GetName(&mName);
    1732            6978 :     return mName;
    1733                 : }
    1734                 : 
    1735                 : JSObject*
    1736            8246 : nsXPCWrappedJSClass::NewOutObject(JSContext* cx, JSObject* scope)
    1737                 : {
    1738            8246 :     return JS_NewObject(cx, nsnull, nsnull, JS_GetGlobalForObject(cx, scope));
    1739                 : }
    1740                 : 
    1741                 : 
    1742                 : NS_IMETHODIMP
    1743               0 : nsXPCWrappedJSClass::DebugDump(PRInt16 depth)
    1744                 : {
    1745                 : #ifdef DEBUG
    1746               0 :     depth-- ;
    1747               0 :     XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %x with mRefCnt = %d", this, mRefCnt.get()));
    1748               0 :     XPC_LOG_INDENT();
    1749                 :         char* name;
    1750               0 :         mInfo->GetName(&name);
    1751               0 :         XPC_LOG_ALWAYS(("interface name is %s", name));
    1752               0 :         if (name)
    1753               0 :             nsMemory::Free(name);
    1754               0 :         char * iid = mIID.ToString();
    1755               0 :         XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
    1756               0 :         if (iid)
    1757               0 :             NS_Free(iid);
    1758               0 :         XPC_LOG_ALWAYS(("InterfaceInfo @ %x", mInfo));
    1759               0 :         uint16_t methodCount = 0;
    1760               0 :         if (depth) {
    1761                 :             uint16_t i;
    1762               0 :             nsCOMPtr<nsIInterfaceInfo> parent;
    1763               0 :             XPC_LOG_INDENT();
    1764               0 :             mInfo->GetParent(getter_AddRefs(parent));
    1765               0 :             XPC_LOG_ALWAYS(("parent @ %x", parent.get()));
    1766               0 :             mInfo->GetMethodCount(&methodCount);
    1767               0 :             XPC_LOG_ALWAYS(("MethodCount = %d", methodCount));
    1768               0 :             mInfo->GetConstantCount(&i);
    1769               0 :             XPC_LOG_ALWAYS(("ConstantCount = %d", i));
    1770               0 :             XPC_LOG_OUTDENT();
    1771                 :         }
    1772               0 :         XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
    1773               0 :         XPC_LOG_ALWAYS(("mDescriptors @ %x count = %d", mDescriptors, methodCount));
    1774               0 :         if (depth && mDescriptors && methodCount) {
    1775               0 :             depth--;
    1776               0 :             XPC_LOG_INDENT();
    1777               0 :             for (uint16_t i = 0; i < methodCount; i++) {
    1778               0 :                 XPC_LOG_ALWAYS(("Method %d is %s%s", \
    1779                 :                                 i, IsReflectable(i) ? "":" NOT ","reflectable"));
    1780                 :             }
    1781               0 :             XPC_LOG_OUTDENT();
    1782               0 :             depth++;
    1783                 :         }
    1784               0 :     XPC_LOG_OUTDENT();
    1785                 : #endif
    1786               0 :     return NS_OK;
    1787                 : }

Generated by: LCOV version 1.7