js/xpconnect/src/XPCWrappedJSClass.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1586 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Sharable code and data for wrapper around JSObjects. */
    1.11 +
    1.12 +#include "xpcprivate.h"
    1.13 +#include "jsprf.h"
    1.14 +#include "nsArrayEnumerator.h"
    1.15 +#include "nsContentUtils.h"
    1.16 +#include "nsWrapperCache.h"
    1.17 +#include "AccessCheck.h"
    1.18 +#include "nsJSUtils.h"
    1.19 +#include "mozilla/Attributes.h"
    1.20 +#include "mozilla/dom/BindingUtils.h"
    1.21 +#include "mozilla/dom/DOMException.h"
    1.22 +#include "mozilla/dom/DOMExceptionBinding.h"
    1.23 +
    1.24 +#include "jsapi.h"
    1.25 +#include "jsfriendapi.h"
    1.26 +
    1.27 +using namespace xpc;
    1.28 +using namespace JS;
    1.29 +using namespace mozilla;
    1.30 +
    1.31 +NS_IMPL_ISUPPORTS(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
    1.32 +
    1.33 +// the value of this variable is never used - we use its address as a sentinel
    1.34 +static uint32_t zero_methods_descriptor;
    1.35 +
    1.36 +bool AutoScriptEvaluate::StartEvaluating(HandleObject scope, JSErrorReporter errorReporter)
    1.37 +{
    1.38 +    NS_PRECONDITION(!mEvaluated, "AutoScriptEvaluate::Evaluate should only be called once");
    1.39 +
    1.40 +    if (!mJSContext)
    1.41 +        return true;
    1.42 +
    1.43 +    mEvaluated = true;
    1.44 +    if (!JS_GetErrorReporter(mJSContext)) {
    1.45 +        JS_SetErrorReporter(mJSContext, errorReporter);
    1.46 +        mErrorReporterSet = true;
    1.47 +    }
    1.48 +
    1.49 +    JS_BeginRequest(mJSContext);
    1.50 +    mAutoCompartment.construct(mJSContext, scope);
    1.51 +
    1.52 +    // Saving the exception state keeps us from interfering with another script
    1.53 +    // that may also be running on this context.  This occurred first with the
    1.54 +    // js debugger, as described in
    1.55 +    // http://bugzilla.mozilla.org/show_bug.cgi?id=88130 but presumably could
    1.56 +    // show up in any situation where a script calls into a wrapped js component
    1.57 +    // on the same context, while the context has a nonzero exception state.
    1.58 +    mState.construct(mJSContext);
    1.59 +
    1.60 +    return true;
    1.61 +}
    1.62 +
    1.63 +AutoScriptEvaluate::~AutoScriptEvaluate()
    1.64 +{
    1.65 +    if (!mJSContext || !mEvaluated)
    1.66 +        return;
    1.67 +    mState.ref().restore();
    1.68 +
    1.69 +    JS_EndRequest(mJSContext);
    1.70 +
    1.71 +    if (mErrorReporterSet)
    1.72 +        JS_SetErrorReporter(mJSContext, nullptr);
    1.73 +}
    1.74 +
    1.75 +// It turns out that some errors may be not worth reporting. So, this
    1.76 +// function is factored out to manage that.
    1.77 +bool xpc_IsReportableErrorCode(nsresult code)
    1.78 +{
    1.79 +    if (NS_SUCCEEDED(code))
    1.80 +        return false;
    1.81 +
    1.82 +    switch (code) {
    1.83 +        // Error codes that we don't want to report as errors...
    1.84 +        // These generally indicate bad interface design AFAIC.
    1.85 +        case NS_ERROR_FACTORY_REGISTER_AGAIN:
    1.86 +        case NS_BASE_STREAM_WOULD_BLOCK:
    1.87 +            return false;
    1.88 +        default:
    1.89 +            return true;
    1.90 +    }
    1.91 +}
    1.92 +
    1.93 +// static
    1.94 +already_AddRefed<nsXPCWrappedJSClass>
    1.95 +nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID)
    1.96 +{
    1.97 +    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
    1.98 +    IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
    1.99 +    nsRefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
   1.100 +
   1.101 +    if (!clasp) {
   1.102 +        nsCOMPtr<nsIInterfaceInfo> info;
   1.103 +        nsXPConnect::XPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
   1.104 +        if (info) {
   1.105 +            bool canScript, isBuiltin;
   1.106 +            if (NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
   1.107 +                NS_SUCCEEDED(info->IsBuiltinClass(&isBuiltin)) && !isBuiltin &&
   1.108 +                nsXPConnect::IsISupportsDescendant(info))
   1.109 +            {
   1.110 +                clasp = new nsXPCWrappedJSClass(cx, aIID, info);
   1.111 +                if (!clasp->mDescriptors)
   1.112 +                    clasp = nullptr;
   1.113 +            }
   1.114 +        }
   1.115 +    }
   1.116 +    return clasp.forget();
   1.117 +}
   1.118 +
   1.119 +nsXPCWrappedJSClass::nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
   1.120 +                                         nsIInterfaceInfo* aInfo)
   1.121 +    : mRuntime(nsXPConnect::GetRuntimeInstance()),
   1.122 +      mInfo(aInfo),
   1.123 +      mName(nullptr),
   1.124 +      mIID(aIID),
   1.125 +      mDescriptors(nullptr)
   1.126 +{
   1.127 +    mRuntime->GetWrappedJSClassMap()->Add(this);
   1.128 +
   1.129 +    uint16_t methodCount;
   1.130 +    if (NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) {
   1.131 +        if (methodCount) {
   1.132 +            int wordCount = (methodCount/32)+1;
   1.133 +            if (nullptr != (mDescriptors = new uint32_t[wordCount])) {
   1.134 +                int i;
   1.135 +                // init flags to 0;
   1.136 +                for (i = wordCount-1; i >= 0; i--)
   1.137 +                    mDescriptors[i] = 0;
   1.138 +
   1.139 +                for (i = 0; i < methodCount; i++) {
   1.140 +                    const nsXPTMethodInfo* info;
   1.141 +                    if (NS_SUCCEEDED(mInfo->GetMethodInfo(i, &info)))
   1.142 +                        SetReflectable(i, XPCConvert::IsMethodReflectable(*info));
   1.143 +                    else {
   1.144 +                        delete [] mDescriptors;
   1.145 +                        mDescriptors = nullptr;
   1.146 +                        break;
   1.147 +                    }
   1.148 +                }
   1.149 +            }
   1.150 +        } else {
   1.151 +            mDescriptors = &zero_methods_descriptor;
   1.152 +        }
   1.153 +    }
   1.154 +}
   1.155 +
   1.156 +nsXPCWrappedJSClass::~nsXPCWrappedJSClass()
   1.157 +{
   1.158 +    if (mDescriptors && mDescriptors != &zero_methods_descriptor)
   1.159 +        delete [] mDescriptors;
   1.160 +    if (mRuntime)
   1.161 +        mRuntime->GetWrappedJSClassMap()->Remove(this);
   1.162 +
   1.163 +    if (mName)
   1.164 +        nsMemory::Free(mName);
   1.165 +}
   1.166 +
   1.167 +JSObject*
   1.168 +nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
   1.169 +                                                  JSObject* jsobjArg,
   1.170 +                                                  REFNSIID aIID)
   1.171 +{
   1.172 +    RootedObject jsobj(cx, jsobjArg);
   1.173 +    JSObject* id;
   1.174 +    RootedValue retval(cx);
   1.175 +    RootedObject retObj(cx);
   1.176 +    bool success = false;
   1.177 +    RootedValue fun(cx);
   1.178 +
   1.179 +    // Don't call the actual function on a content object. We'll determine
   1.180 +    // whether or not a content object is capable of implementing the
   1.181 +    // interface (i.e. whether the interface is scriptable) and most content
   1.182 +    // objects don't have QI implementations anyway. Also see bug 503926.
   1.183 +    if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(jsobj))) {
   1.184 +        return nullptr;
   1.185 +    }
   1.186 +
   1.187 +    // OK, it looks like we'll be calling into JS code.
   1.188 +    AutoScriptEvaluate scriptEval(cx);
   1.189 +
   1.190 +    // XXX we should install an error reporter that will send reports to
   1.191 +    // the JS error console service.
   1.192 +    if (!scriptEval.StartEvaluating(jsobj))
   1.193 +        return nullptr;
   1.194 +
   1.195 +    // check upfront for the existence of the function property
   1.196 +    HandleId funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
   1.197 +    if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
   1.198 +        return nullptr;
   1.199 +
   1.200 +    // Ensure that we are asking for a scriptable interface.
   1.201 +    // NB:  It's important for security that this check is here rather
   1.202 +    // than later, since it prevents untrusted objects from implementing
   1.203 +    // some interfaces in JS and aggregating a trusted object to
   1.204 +    // implement intentionally (for security) unscriptable interfaces.
   1.205 +    // We so often ask for nsISupports that we can short-circuit the test...
   1.206 +    if (!aIID.Equals(NS_GET_IID(nsISupports))) {
   1.207 +        nsCOMPtr<nsIInterfaceInfo> info;
   1.208 +        nsXPConnect::XPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
   1.209 +        if (!info)
   1.210 +            return nullptr;
   1.211 +        bool canScript, isBuiltin;
   1.212 +        if (NS_FAILED(info->IsScriptable(&canScript)) || !canScript ||
   1.213 +            NS_FAILED(info->IsBuiltinClass(&isBuiltin)) || isBuiltin)
   1.214 +            return nullptr;
   1.215 +    }
   1.216 +
   1.217 +    id = xpc_NewIDObject(cx, jsobj, aIID);
   1.218 +    if (id) {
   1.219 +        // Throwing NS_NOINTERFACE is the prescribed way to fail QI from JS. It
   1.220 +        // is not an exception that is ever worth reporting, but we don't want
   1.221 +        // to eat all exceptions either.
   1.222 +
   1.223 +        {
   1.224 +            AutoSaveContextOptions asco(cx);
   1.225 +            ContextOptionsRef(cx).setDontReportUncaught(true);
   1.226 +            RootedValue arg(cx, JS::ObjectValue(*id));
   1.227 +            success = JS_CallFunctionValue(cx, jsobj, fun, arg, &retval);
   1.228 +        }
   1.229 +
   1.230 +        if (!success && JS_IsExceptionPending(cx)) {
   1.231 +            RootedValue jsexception(cx, NullValue());
   1.232 +
   1.233 +            if (JS_GetPendingException(cx, &jsexception)) {
   1.234 +                nsresult rv;
   1.235 +                if (jsexception.isObject()) {
   1.236 +                    // XPConnect may have constructed an object to represent a
   1.237 +                    // C++ QI failure. See if that is the case.
   1.238 +                    using namespace mozilla::dom;
   1.239 +                    Exception *e = nullptr;
   1.240 +                    UNWRAP_OBJECT(Exception, &jsexception.toObject(), e);
   1.241 +
   1.242 +                    if (e &&
   1.243 +                        NS_SUCCEEDED(e->GetResult(&rv)) &&
   1.244 +                        rv == NS_NOINTERFACE) {
   1.245 +                        JS_ClearPendingException(cx);
   1.246 +                    }
   1.247 +                } else if (JSVAL_IS_NUMBER(jsexception)) {
   1.248 +                    // JS often throws an nsresult.
   1.249 +                    if (JSVAL_IS_DOUBLE(jsexception))
   1.250 +                        // Visual Studio 9 doesn't allow casting directly from
   1.251 +                        // a double to an enumeration type, contrary to
   1.252 +                        // 5.2.9(10) of C++11, so add an intermediate cast.
   1.253 +                        rv = (nsresult)(uint32_t)(JSVAL_TO_DOUBLE(jsexception));
   1.254 +                    else
   1.255 +                        rv = (nsresult)(JSVAL_TO_INT(jsexception));
   1.256 +
   1.257 +                    if (rv == NS_NOINTERFACE)
   1.258 +                        JS_ClearPendingException(cx);
   1.259 +                }
   1.260 +            }
   1.261 +
   1.262 +            // Don't report if reporting was disabled by someone else.
   1.263 +            if (!ContextOptionsRef(cx).dontReportUncaught())
   1.264 +                JS_ReportPendingException(cx);
   1.265 +        } else if (!success) {
   1.266 +            NS_WARNING("QI hook ran OOMed - this is probably a bug!");
   1.267 +        }
   1.268 +    }
   1.269 +
   1.270 +    if (success)
   1.271 +        success = JS_ValueToObject(cx, retval, &retObj);
   1.272 +
   1.273 +    return success ? retObj.get() : nullptr;
   1.274 +}
   1.275 +
   1.276 +/***************************************************************************/
   1.277 +
   1.278 +static bool
   1.279 +GetNamedPropertyAsVariantRaw(XPCCallContext& ccx,
   1.280 +                             HandleObject aJSObj,
   1.281 +                             HandleId aName,
   1.282 +                             nsIVariant** aResult,
   1.283 +                             nsresult* pErr)
   1.284 +{
   1.285 +    nsXPTType type = nsXPTType((uint8_t)TD_INTERFACE_TYPE);
   1.286 +    RootedValue val(ccx);
   1.287 +
   1.288 +    return JS_GetPropertyById(ccx, aJSObj, aName, &val) &&
   1.289 +           // Note that this always takes the T_INTERFACE path through
   1.290 +           // JSData2Native, so the value passed for useAllocator
   1.291 +           // doesn't really matter. We pass true for consistency.
   1.292 +           XPCConvert::JSData2Native(aResult, val, type, true,
   1.293 +                                     &NS_GET_IID(nsIVariant), pErr);
   1.294 +}
   1.295 +
   1.296 +// static
   1.297 +nsresult
   1.298 +nsXPCWrappedJSClass::GetNamedPropertyAsVariant(XPCCallContext& ccx,
   1.299 +                                               JSObject* aJSObjArg,
   1.300 +                                               const nsAString& aName,
   1.301 +                                               nsIVariant** aResult)
   1.302 +{
   1.303 +    JSContext* cx = ccx.GetJSContext();
   1.304 +    RootedObject aJSObj(cx, aJSObjArg);
   1.305 +
   1.306 +    AutoScriptEvaluate scriptEval(cx);
   1.307 +    if (!scriptEval.StartEvaluating(aJSObj))
   1.308 +        return NS_ERROR_FAILURE;
   1.309 +
   1.310 +    // Wrap the string in a jsval after the AutoScriptEvaluate, so that the
   1.311 +    // resulting value ends up in the correct compartment.
   1.312 +    nsStringBuffer* buf;
   1.313 +    RootedValue value(cx);
   1.314 +    if (!XPCStringConvert::ReadableToJSVal(ccx, aName, &buf, &value))
   1.315 +        return NS_ERROR_OUT_OF_MEMORY;
   1.316 +    if (buf)
   1.317 +        buf->AddRef();
   1.318 +
   1.319 +    RootedId id(cx);
   1.320 +    nsresult rv = NS_OK;
   1.321 +    if (!JS_ValueToId(cx, value, &id) ||
   1.322 +        !GetNamedPropertyAsVariantRaw(ccx, aJSObj, id, aResult, &rv)) {
   1.323 +        if (NS_FAILED(rv))
   1.324 +            return rv;
   1.325 +        return NS_ERROR_FAILURE;
   1.326 +    }
   1.327 +    return NS_OK;
   1.328 +}
   1.329 +
   1.330 +/***************************************************************************/
   1.331 +
   1.332 +// static
   1.333 +nsresult
   1.334 +nsXPCWrappedJSClass::BuildPropertyEnumerator(XPCCallContext& ccx,
   1.335 +                                             JSObject* aJSObjArg,
   1.336 +                                             nsISimpleEnumerator** aEnumerate)
   1.337 +{
   1.338 +    JSContext* cx = ccx.GetJSContext();
   1.339 +    RootedObject aJSObj(cx, aJSObjArg);
   1.340 +
   1.341 +    AutoScriptEvaluate scriptEval(cx);
   1.342 +    if (!scriptEval.StartEvaluating(aJSObj))
   1.343 +        return NS_ERROR_FAILURE;
   1.344 +
   1.345 +    AutoIdArray idArray(cx, JS_Enumerate(cx, aJSObj));
   1.346 +    if (!idArray)
   1.347 +        return NS_ERROR_FAILURE;
   1.348 +
   1.349 +    nsCOMArray<nsIProperty> propertyArray(idArray.length());
   1.350 +    RootedId idName(cx);
   1.351 +    for (size_t i = 0; i < idArray.length(); i++) {
   1.352 +        idName = idArray[i];
   1.353 +
   1.354 +        nsCOMPtr<nsIVariant> value;
   1.355 +        nsresult rv;
   1.356 +        if (!GetNamedPropertyAsVariantRaw(ccx, aJSObj, idName,
   1.357 +                                          getter_AddRefs(value), &rv)) {
   1.358 +            if (NS_FAILED(rv))
   1.359 +                return rv;
   1.360 +            return NS_ERROR_FAILURE;
   1.361 +        }
   1.362 +
   1.363 +        RootedValue jsvalName(cx);
   1.364 +        if (!JS_IdToValue(cx, idName, &jsvalName))
   1.365 +            return NS_ERROR_FAILURE;
   1.366 +
   1.367 +        JSString* name = ToString(cx, jsvalName);
   1.368 +        if (!name)
   1.369 +            return NS_ERROR_FAILURE;
   1.370 +
   1.371 +        size_t length;
   1.372 +        const jschar *chars = JS_GetStringCharsAndLength(cx, name, &length);
   1.373 +        if (!chars)
   1.374 +            return NS_ERROR_FAILURE;
   1.375 +
   1.376 +        nsCOMPtr<nsIProperty> property =
   1.377 +            new xpcProperty(chars, (uint32_t) length, value);
   1.378 +
   1.379 +        if (!propertyArray.AppendObject(property))
   1.380 +            return NS_ERROR_FAILURE;
   1.381 +    }
   1.382 +
   1.383 +    return NS_NewArrayEnumerator(aEnumerate, propertyArray);
   1.384 +}
   1.385 +
   1.386 +/***************************************************************************/
   1.387 +
   1.388 +NS_IMPL_ISUPPORTS(xpcProperty, nsIProperty)
   1.389 +
   1.390 +xpcProperty::xpcProperty(const char16_t* aName, uint32_t aNameLen,
   1.391 +                         nsIVariant* aValue)
   1.392 +    : mName(aName, aNameLen), mValue(aValue)
   1.393 +{
   1.394 +}
   1.395 +
   1.396 +/* readonly attribute AString name; */
   1.397 +NS_IMETHODIMP xpcProperty::GetName(nsAString & aName)
   1.398 +{
   1.399 +    aName.Assign(mName);
   1.400 +    return NS_OK;
   1.401 +}
   1.402 +
   1.403 +/* readonly attribute nsIVariant value; */
   1.404 +NS_IMETHODIMP xpcProperty::GetValue(nsIVariant * *aValue)
   1.405 +{
   1.406 +    nsCOMPtr<nsIVariant> rval = mValue;
   1.407 +    rval.forget(aValue);
   1.408 +    return NS_OK;
   1.409 +}
   1.410 +
   1.411 +/***************************************************************************/
   1.412 +// This 'WrappedJSIdentity' class and singleton allow us to figure out if
   1.413 +// any given nsISupports* is implemented by a WrappedJS object. This is done
   1.414 +// using a QueryInterface call on the interface pointer with our ID. If
   1.415 +// that call returns NS_OK and the pointer is to our singleton, then the
   1.416 +// interface must be implemented by a WrappedJS object. NOTE: the
   1.417 +// 'WrappedJSIdentity' object is not a real XPCOM object and should not be
   1.418 +// used for anything else (hence it is declared in this implementation file).
   1.419 +
   1.420 +// {5C5C3BB0-A9BA-11d2-BA64-00805F8A5DD7}
   1.421 +#define NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID                           \
   1.422 +{ 0x5c5c3bb0, 0xa9ba, 0x11d2,                                                 \
   1.423 +  { 0xba, 0x64, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
   1.424 +
   1.425 +class WrappedJSIdentity
   1.426 +{
   1.427 +    // no instance methods...
   1.428 +public:
   1.429 +    NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
   1.430 +
   1.431 +    static void* GetSingleton()
   1.432 +    {
   1.433 +        static WrappedJSIdentity* singleton = nullptr;
   1.434 +        if (!singleton)
   1.435 +            singleton = new WrappedJSIdentity();
   1.436 +        return (void*) singleton;
   1.437 +    }
   1.438 +};
   1.439 +
   1.440 +NS_DEFINE_STATIC_IID_ACCESSOR(WrappedJSIdentity,
   1.441 +                              NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
   1.442 +
   1.443 +/***************************************************************************/
   1.444 +
   1.445 +// static
   1.446 +bool
   1.447 +nsXPCWrappedJSClass::IsWrappedJS(nsISupports* aPtr)
   1.448 +{
   1.449 +    void* result;
   1.450 +    NS_PRECONDITION(aPtr, "null pointer");
   1.451 +    return aPtr &&
   1.452 +           NS_OK == aPtr->QueryInterface(NS_GET_IID(WrappedJSIdentity), &result) &&
   1.453 +           result == WrappedJSIdentity::GetSingleton();
   1.454 +}
   1.455 +
   1.456 +// NB: This will return the top JSContext on the JSContext stack if there is one,
   1.457 +// before attempting to get the context from the wrapped JS object.
   1.458 +static JSContext *
   1.459 +GetContextFromObjectOrDefault(nsXPCWrappedJS* wrapper)
   1.460 +{
   1.461 +    // First, try the cx stack.
   1.462 +    XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
   1.463 +    if (stack->Peek())
   1.464 +        return stack->Peek();
   1.465 +
   1.466 +    // If the cx stack is empty, try the wrapper's JSObject.
   1.467 +    JSCompartment *c = js::GetObjectCompartment(wrapper->GetJSObject());
   1.468 +    XPCContext *xpcc = EnsureCompartmentPrivate(c)->scope->GetContext();
   1.469 +    if (xpcc) {
   1.470 +        JSContext *cx = xpcc->GetJSContext();
   1.471 +        JS_AbortIfWrongThread(JS_GetRuntime(cx));
   1.472 +        return cx;
   1.473 +    }
   1.474 +
   1.475 +    // Fall back to the safe JSContext.
   1.476 +    return stack->GetSafeJSContext();
   1.477 +}
   1.478 +
   1.479 +NS_IMETHODIMP
   1.480 +nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
   1.481 +                                             REFNSIID aIID,
   1.482 +                                             void** aInstancePtr)
   1.483 +{
   1.484 +    if (aIID.Equals(NS_GET_IID(nsIXPConnectJSObjectHolder))) {
   1.485 +        NS_ADDREF(self);
   1.486 +        *aInstancePtr = (void*) static_cast<nsIXPConnectJSObjectHolder*>(self);
   1.487 +        return NS_OK;
   1.488 +    }
   1.489 +
   1.490 +    // Objects internal to xpconnect are the only objects that even know *how*
   1.491 +    // to ask for this iid. And none of them bother refcounting the thing.
   1.492 +    if (aIID.Equals(NS_GET_IID(WrappedJSIdentity))) {
   1.493 +        // asking to find out if this is a wrapper object
   1.494 +        *aInstancePtr = WrappedJSIdentity::GetSingleton();
   1.495 +        return NS_OK;
   1.496 +    }
   1.497 +
   1.498 +    if (aIID.Equals(NS_GET_IID(nsIPropertyBag))) {
   1.499 +        // We only want to expose one implementation from our aggregate.
   1.500 +        nsXPCWrappedJS* root = self->GetRootWrapper();
   1.501 +
   1.502 +        if (!root->IsValid()) {
   1.503 +            *aInstancePtr = nullptr;
   1.504 +            return NS_NOINTERFACE;
   1.505 +        }
   1.506 +
   1.507 +        NS_ADDREF(root);
   1.508 +        *aInstancePtr = (void*) static_cast<nsIPropertyBag*>(root);
   1.509 +        return NS_OK;
   1.510 +    }
   1.511 +
   1.512 +    // We can't have a cached wrapper.
   1.513 +    if (aIID.Equals(NS_GET_IID(nsWrapperCache))) {
   1.514 +        *aInstancePtr = nullptr;
   1.515 +        return NS_NOINTERFACE;
   1.516 +    }
   1.517 +
   1.518 +    AutoPushJSContext context(GetContextFromObjectOrDefault(self));
   1.519 +    XPCCallContext ccx(NATIVE_CALLER, context);
   1.520 +    if (!ccx.IsValid()) {
   1.521 +        *aInstancePtr = nullptr;
   1.522 +        return NS_NOINTERFACE;
   1.523 +    }
   1.524 +
   1.525 +    // We support nsISupportsWeakReference iff the root wrapped JSObject
   1.526 +    // claims to support it in its QueryInterface implementation.
   1.527 +    if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) {
   1.528 +        // We only want to expose one implementation from our aggregate.
   1.529 +        nsXPCWrappedJS* root = self->GetRootWrapper();
   1.530 +
   1.531 +        // Fail if JSObject doesn't claim support for nsISupportsWeakReference
   1.532 +        if (!root->IsValid() ||
   1.533 +            !CallQueryInterfaceOnJSObject(ccx, root->GetJSObject(), aIID)) {
   1.534 +            *aInstancePtr = nullptr;
   1.535 +            return NS_NOINTERFACE;
   1.536 +        }
   1.537 +
   1.538 +        NS_ADDREF(root);
   1.539 +        *aInstancePtr = (void*) static_cast<nsISupportsWeakReference*>(root);
   1.540 +        return NS_OK;
   1.541 +    }
   1.542 +
   1.543 +    // Checks for any existing wrapper explicitly constructed for this iid.
   1.544 +    // This includes the current 'self' wrapper. This also deals with the
   1.545 +    // nsISupports case (for which it returns mRoot).
   1.546 +    // Also check if asking for an interface from which one of our wrappers inherits.
   1.547 +    if (nsXPCWrappedJS* sibling = self->FindOrFindInherited(aIID)) {
   1.548 +        NS_ADDREF(sibling);
   1.549 +        *aInstancePtr = sibling->GetXPTCStub();
   1.550 +        return NS_OK;
   1.551 +    }
   1.552 +
   1.553 +    // else we do the more expensive stuff...
   1.554 +
   1.555 +    // check if the JSObject claims to implement this interface
   1.556 +    RootedObject jsobj(ccx, CallQueryInterfaceOnJSObject(ccx, self->GetJSObject(),
   1.557 +                                                         aIID));
   1.558 +    if (jsobj) {
   1.559 +        // We can't use XPConvert::JSObject2NativeInterface() here
   1.560 +        // since that can find a XPCWrappedNative directly on the
   1.561 +        // proto chain, and we don't want that here. We need to find
   1.562 +        // the actual JS object that claimed it supports the interface
   1.563 +        // we're looking for or we'll potentially bypass security
   1.564 +        // checks etc by calling directly through to a native found on
   1.565 +        // the prototype chain.
   1.566 +        //
   1.567 +        // Instead, simply do the nsXPCWrappedJS part of
   1.568 +        // XPConvert::JSObject2NativeInterface() here to make sure we
   1.569 +        // get a new (or used) nsXPCWrappedJS.
   1.570 +        nsXPCWrappedJS* wrapper;
   1.571 +        nsresult rv = nsXPCWrappedJS::GetNewOrUsed(jsobj, aIID, &wrapper);
   1.572 +        if (NS_SUCCEEDED(rv) && wrapper) {
   1.573 +            // We need to go through the QueryInterface logic to make
   1.574 +            // this return the right thing for the various 'special'
   1.575 +            // interfaces; e.g.  nsIPropertyBag.
   1.576 +            rv = wrapper->QueryInterface(aIID, aInstancePtr);
   1.577 +            NS_RELEASE(wrapper);
   1.578 +            return rv;
   1.579 +        }
   1.580 +    }
   1.581 +
   1.582 +    // else...
   1.583 +    // no can do
   1.584 +    *aInstancePtr = nullptr;
   1.585 +    return NS_NOINTERFACE;
   1.586 +}
   1.587 +
   1.588 +JSObject*
   1.589 +nsXPCWrappedJSClass::GetRootJSObject(JSContext* cx, JSObject* aJSObjArg)
   1.590 +{
   1.591 +    RootedObject aJSObj(cx, aJSObjArg);
   1.592 +    JSObject* result = CallQueryInterfaceOnJSObject(cx, aJSObj,
   1.593 +                                                    NS_GET_IID(nsISupports));
   1.594 +    if (!result)
   1.595 +        return aJSObj;
   1.596 +    JSObject* inner = js::UncheckedUnwrap(result);
   1.597 +    if (inner)
   1.598 +        return inner;
   1.599 +    return result;
   1.600 +}
   1.601 +
   1.602 +void
   1.603 +xpcWrappedJSErrorReporter(JSContext *cx, const char *message,
   1.604 +                          JSErrorReport *report)
   1.605 +{
   1.606 +    if (report) {
   1.607 +        // If it is an exception report, then we can just deal with the
   1.608 +        // exception later (if not caught in the JS code).
   1.609 +        if (JSREPORT_IS_EXCEPTION(report->flags)) {
   1.610 +            // XXX We have a problem with error reports from uncaught exceptions.
   1.611 +            //
   1.612 +            // http://bugzilla.mozilla.org/show_bug.cgi?id=66453
   1.613 +            //
   1.614 +            // The issue is...
   1.615 +            //
   1.616 +            // We can't assume that the exception will *stay* uncaught. So, if
   1.617 +            // we build an nsIXPCException here and the underlying exception
   1.618 +            // really is caught before our script is done running then we blow
   1.619 +            // it by returning failure to our caller when the script didn't
   1.620 +            // really fail. However, This report contains error location info
   1.621 +            // that is no longer available after the script is done. So, if the
   1.622 +            // exception really is not caught (and is a non-engine exception)
   1.623 +            // then we've lost the oportunity to capture the script location
   1.624 +            // info that we *could* have captured here.
   1.625 +            //
   1.626 +            // This is expecially an issue with nested evaluations.
   1.627 +            //
   1.628 +            // Perhaps we could capture an expception here and store it as
   1.629 +            // 'provisional' and then later if there is a pending exception
   1.630 +            // when the script is done then we could maybe compare that in some
   1.631 +            // way with the 'provisional' one in which we captured location info.
   1.632 +            // We would not want to assume that the one discovered here is the
   1.633 +            // same one that is later detected. This could cause us to lie.
   1.634 +            //
   1.635 +            // The thing is. we do not currently store the right stuff to compare
   1.636 +            // these two nsIXPCExceptions (triggered by the same exception jsval
   1.637 +            // in the engine). Maybe we should store the jsval and compare that?
   1.638 +            // Maybe without even rooting it since we will not dereference it.
   1.639 +            // This is inexact, but maybe the right thing to do?
   1.640 +            //
   1.641 +            // if (report->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)) ...
   1.642 +            //
   1.643 +
   1.644 +            return;
   1.645 +        }
   1.646 +
   1.647 +        if (JSREPORT_IS_WARNING(report->flags)) {
   1.648 +            // XXX printf the warning (#ifdef DEBUG only!).
   1.649 +            // XXX send the warning to the console service.
   1.650 +            return;
   1.651 +        }
   1.652 +    }
   1.653 +
   1.654 +    XPCCallContext ccx(NATIVE_CALLER, cx);
   1.655 +    if (!ccx.IsValid())
   1.656 +        return;
   1.657 +
   1.658 +    nsCOMPtr<nsIException> e;
   1.659 +    XPCConvert::JSErrorToXPCException(message, nullptr, nullptr, report,
   1.660 +                                      getter_AddRefs(e));
   1.661 +    if (e)
   1.662 +        ccx.GetXPCContext()->SetException(e);
   1.663 +}
   1.664 +
   1.665 +bool
   1.666 +nsXPCWrappedJSClass::GetArraySizeFromParam(JSContext* cx,
   1.667 +                                           const XPTMethodDescriptor* method,
   1.668 +                                           const nsXPTParamInfo& param,
   1.669 +                                           uint16_t methodIndex,
   1.670 +                                           uint8_t paramIndex,
   1.671 +                                           nsXPTCMiniVariant* nativeParams,
   1.672 +                                           uint32_t* result)
   1.673 +{
   1.674 +    uint8_t argnum;
   1.675 +    nsresult rv;
   1.676 +
   1.677 +    rv = mInfo->GetSizeIsArgNumberForParam(methodIndex, &param, 0, &argnum);
   1.678 +    if (NS_FAILED(rv))
   1.679 +        return false;
   1.680 +
   1.681 +    const nsXPTParamInfo& arg_param = method->params[argnum];
   1.682 +
   1.683 +    // This should be enforced by the xpidl compiler, but it's not.
   1.684 +    // See bug 695235.
   1.685 +    MOZ_ASSERT(arg_param.GetType().TagPart() == nsXPTType::T_U32,
   1.686 +               "size_is references parameter of invalid type.");
   1.687 +
   1.688 +    if (arg_param.IsIndirect())
   1.689 +        *result = *(uint32_t*)nativeParams[argnum].val.p;
   1.690 +    else
   1.691 +        *result = nativeParams[argnum].val.u32;
   1.692 +
   1.693 +    return true;
   1.694 +}
   1.695 +
   1.696 +bool
   1.697 +nsXPCWrappedJSClass::GetInterfaceTypeFromParam(JSContext* cx,
   1.698 +                                               const XPTMethodDescriptor* method,
   1.699 +                                               const nsXPTParamInfo& param,
   1.700 +                                               uint16_t methodIndex,
   1.701 +                                               const nsXPTType& type,
   1.702 +                                               nsXPTCMiniVariant* nativeParams,
   1.703 +                                               nsID* result)
   1.704 +{
   1.705 +    uint8_t type_tag = type.TagPart();
   1.706 +
   1.707 +    if (type_tag == nsXPTType::T_INTERFACE) {
   1.708 +        if (NS_SUCCEEDED(GetInterfaceInfo()->
   1.709 +                         GetIIDForParamNoAlloc(methodIndex, &param, result))) {
   1.710 +            return true;
   1.711 +        }
   1.712 +    } else if (type_tag == nsXPTType::T_INTERFACE_IS) {
   1.713 +        uint8_t argnum;
   1.714 +        nsresult rv;
   1.715 +        rv = mInfo->GetInterfaceIsArgNumberForParam(methodIndex,
   1.716 +                                                    &param, &argnum);
   1.717 +        if (NS_FAILED(rv))
   1.718 +            return false;
   1.719 +
   1.720 +        const nsXPTParamInfo& arg_param = method->params[argnum];
   1.721 +        const nsXPTType& arg_type = arg_param.GetType();
   1.722 +
   1.723 +        if (arg_type.TagPart() == nsXPTType::T_IID) {
   1.724 +            if (arg_param.IsIndirect()) {
   1.725 +                nsID** p = (nsID**) nativeParams[argnum].val.p;
   1.726 +                if (!p || !*p)
   1.727 +                    return false;
   1.728 +                *result = **p;
   1.729 +            } else {
   1.730 +                nsID* p = (nsID*) nativeParams[argnum].val.p;
   1.731 +                if (!p)
   1.732 +                    return false;
   1.733 +                *result = *p;
   1.734 +            }
   1.735 +            return true;
   1.736 +        }
   1.737 +    }
   1.738 +    return false;
   1.739 +}
   1.740 +
   1.741 +void
   1.742 +nsXPCWrappedJSClass::CleanupPointerArray(const nsXPTType& datum_type,
   1.743 +                                         uint32_t array_count,
   1.744 +                                         void** arrayp)
   1.745 +{
   1.746 +    if (datum_type.IsInterfacePointer()) {
   1.747 +        nsISupports** pp = (nsISupports**) arrayp;
   1.748 +        for (uint32_t k = 0; k < array_count; k++) {
   1.749 +            nsISupports* p = pp[k];
   1.750 +            NS_IF_RELEASE(p);
   1.751 +        }
   1.752 +    } else {
   1.753 +        void** pp = (void**) arrayp;
   1.754 +        for (uint32_t k = 0; k < array_count; k++) {
   1.755 +            void* p = pp[k];
   1.756 +            if (p) nsMemory::Free(p);
   1.757 +        }
   1.758 +    }
   1.759 +}
   1.760 +
   1.761 +void
   1.762 +nsXPCWrappedJSClass::CleanupPointerTypeObject(const nsXPTType& type,
   1.763 +                                              void** pp)
   1.764 +{
   1.765 +    MOZ_ASSERT(pp,"null pointer");
   1.766 +    if (type.IsInterfacePointer()) {
   1.767 +        nsISupports* p = *((nsISupports**)pp);
   1.768 +        if (p) p->Release();
   1.769 +    } else {
   1.770 +        void* p = *((void**)pp);
   1.771 +        if (p) nsMemory::Free(p);
   1.772 +    }
   1.773 +}
   1.774 +
   1.775 +class AutoClearPendingException
   1.776 +{
   1.777 +public:
   1.778 +  AutoClearPendingException(JSContext *cx) : mCx(cx) { }
   1.779 +  ~AutoClearPendingException() { JS_ClearPendingException(mCx); }
   1.780 +private:
   1.781 +  JSContext* mCx;
   1.782 +};
   1.783 +
   1.784 +nsresult
   1.785 +nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
   1.786 +                                       const char * aPropertyName,
   1.787 +                                       const char * anInterfaceName,
   1.788 +                                       bool aForceReport)
   1.789 +{
   1.790 +    XPCContext * xpcc = ccx.GetXPCContext();
   1.791 +    JSContext * cx = ccx.GetJSContext();
   1.792 +    nsCOMPtr<nsIException> xpc_exception;
   1.793 +    /* this one would be set by our error reporter */
   1.794 +
   1.795 +    xpcc->GetException(getter_AddRefs(xpc_exception));
   1.796 +    if (xpc_exception)
   1.797 +        xpcc->SetException(nullptr);
   1.798 +
   1.799 +    // get this right away in case we do something below to cause JS code
   1.800 +    // to run on this JSContext
   1.801 +    nsresult pending_result = xpcc->GetPendingResult();
   1.802 +
   1.803 +    RootedValue js_exception(cx);
   1.804 +    bool is_js_exception = JS_GetPendingException(cx, &js_exception);
   1.805 +
   1.806 +    /* JS might throw an expection whether the reporter was called or not */
   1.807 +    if (is_js_exception) {
   1.808 +        if (!xpc_exception)
   1.809 +            XPCConvert::JSValToXPCException(&js_exception, anInterfaceName,
   1.810 +                                            aPropertyName,
   1.811 +                                            getter_AddRefs(xpc_exception));
   1.812 +
   1.813 +        /* cleanup and set failed even if we can't build an exception */
   1.814 +        if (!xpc_exception) {
   1.815 +            XPCJSRuntime::Get()->SetPendingException(nullptr); // XXX necessary?
   1.816 +        }
   1.817 +    }
   1.818 +
   1.819 +    AutoClearPendingException acpe(cx);
   1.820 +
   1.821 +    if (xpc_exception) {
   1.822 +        nsresult e_result;
   1.823 +        if (NS_SUCCEEDED(xpc_exception->GetResult(&e_result))) {
   1.824 +            // Figure out whether or not we should report this exception.
   1.825 +            bool reportable = xpc_IsReportableErrorCode(e_result);
   1.826 +            if (reportable) {
   1.827 +                // Always want to report forced exceptions and XPConnect's own
   1.828 +                // errors.
   1.829 +                reportable = aForceReport ||
   1.830 +                    NS_ERROR_GET_MODULE(e_result) == NS_ERROR_MODULE_XPCONNECT;
   1.831 +
   1.832 +                // See if an environment variable was set or someone has told us
   1.833 +                // that a user pref was set indicating that we should report all
   1.834 +                // exceptions.
   1.835 +                if (!reportable)
   1.836 +                    reportable = nsXPConnect::ReportAllJSExceptions();
   1.837 +
   1.838 +                // Finally, check to see if this is the last JS frame on the
   1.839 +                // stack. If so then we always want to report it.
   1.840 +                if (!reportable)
   1.841 +                    reportable = !JS::DescribeScriptedCaller(cx);
   1.842 +
   1.843 +                // Ugly special case for GetInterface. It's "special" in the
   1.844 +                // same way as QueryInterface in that a failure is not
   1.845 +                // exceptional and shouldn't be reported. We have to do this
   1.846 +                // check here instead of in xpcwrappedjs (like we do for QI) to
   1.847 +                // avoid adding extra code to all xpcwrappedjs objects.
   1.848 +                if (reportable && e_result == NS_ERROR_NO_INTERFACE &&
   1.849 +                    !strcmp(anInterfaceName, "nsIInterfaceRequestor") &&
   1.850 +                    !strcmp(aPropertyName, "getInterface")) {
   1.851 +                    reportable = false;
   1.852 +                }
   1.853 +
   1.854 +                // More special case, see bug 877760.
   1.855 +                if (e_result == NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) {
   1.856 +                    reportable = false;
   1.857 +                }
   1.858 +            }
   1.859 +
   1.860 +            // Try to use the error reporter set on the context to handle this
   1.861 +            // error if it came from a JS exception.
   1.862 +            if (reportable && is_js_exception &&
   1.863 +                JS_GetErrorReporter(cx) != xpcWrappedJSErrorReporter)
   1.864 +            {
   1.865 +                // If the error reporter ignores the error, it will call
   1.866 +                // xpc->MarkErrorUnreported().
   1.867 +                xpcc->ClearUnreportedError();
   1.868 +                reportable = !JS_ReportPendingException(cx);
   1.869 +                if (!xpcc->WasErrorReported())
   1.870 +                    reportable = true;
   1.871 +            }
   1.872 +
   1.873 +            if (reportable) {
   1.874 +                if (nsContentUtils::DOMWindowDumpEnabled()) {
   1.875 +                    static const char line[] =
   1.876 +                        "************************************************************\n";
   1.877 +                    static const char preamble[] =
   1.878 +                        "* Call to xpconnect wrapped JSObject produced this error:  *\n";
   1.879 +                    static const char cant_get_text[] =
   1.880 +                        "FAILED TO GET TEXT FROM EXCEPTION\n";
   1.881 +
   1.882 +                    fputs(line, stdout);
   1.883 +                    fputs(preamble, stdout);
   1.884 +                    nsCString text;
   1.885 +                    if (NS_SUCCEEDED(xpc_exception->ToString(text)) &&
   1.886 +                        !text.IsEmpty()) {
   1.887 +                        fputs(text.get(), stdout);
   1.888 +                        fputs("\n", stdout);
   1.889 +                    } else
   1.890 +                        fputs(cant_get_text, stdout);
   1.891 +                    fputs(line, stdout);
   1.892 +                }
   1.893 +
   1.894 +                // Log the exception to the JS Console, so that users can do
   1.895 +                // something with it.
   1.896 +                nsCOMPtr<nsIConsoleService> consoleService
   1.897 +                    (do_GetService(XPC_CONSOLE_CONTRACTID));
   1.898 +                if (nullptr != consoleService) {
   1.899 +                    nsresult rv;
   1.900 +                    nsCOMPtr<nsIScriptError> scriptError;
   1.901 +                    nsCOMPtr<nsISupports> errorData;
   1.902 +                    rv = xpc_exception->GetData(getter_AddRefs(errorData));
   1.903 +                    if (NS_SUCCEEDED(rv))
   1.904 +                        scriptError = do_QueryInterface(errorData);
   1.905 +
   1.906 +                    if (nullptr == scriptError) {
   1.907 +                        // No luck getting one from the exception, so
   1.908 +                        // try to cook one up.
   1.909 +                        scriptError = do_CreateInstance(XPC_SCRIPT_ERROR_CONTRACTID);
   1.910 +                        if (nullptr != scriptError) {
   1.911 +                            nsCString newMessage;
   1.912 +                            rv = xpc_exception->ToString(newMessage);
   1.913 +                            if (NS_SUCCEEDED(rv)) {
   1.914 +                                // try to get filename, lineno from the first
   1.915 +                                // stack frame location.
   1.916 +                                int32_t lineNumber = 0;
   1.917 +                                nsString sourceName;
   1.918 +
   1.919 +                                nsCOMPtr<nsIStackFrame> location;
   1.920 +                                xpc_exception->
   1.921 +                                    GetLocation(getter_AddRefs(location));
   1.922 +                                if (location) {
   1.923 +                                    // Get line number w/o checking; 0 is ok.
   1.924 +                                    location->GetLineNumber(&lineNumber);
   1.925 +
   1.926 +                                    // get a filename.
   1.927 +                                    rv = location->GetFilename(sourceName);
   1.928 +                                }
   1.929 +
   1.930 +                                rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(newMessage),
   1.931 +                                                                   sourceName,
   1.932 +                                                                   EmptyString(),
   1.933 +                                                                   lineNumber, 0, 0,
   1.934 +                                                                   "XPConnect JavaScript",
   1.935 +                                                                   nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
   1.936 +                                if (NS_FAILED(rv))
   1.937 +                                    scriptError = nullptr;
   1.938 +                            }
   1.939 +                        }
   1.940 +                    }
   1.941 +                    if (nullptr != scriptError)
   1.942 +                        consoleService->LogMessage(scriptError);
   1.943 +                }
   1.944 +            }
   1.945 +            // Whether or not it passes the 'reportable' test, it might
   1.946 +            // still be an error and we have to do the right thing here...
   1.947 +            if (NS_FAILED(e_result)) {
   1.948 +                XPCJSRuntime::Get()->SetPendingException(xpc_exception);
   1.949 +                return e_result;
   1.950 +            }
   1.951 +        }
   1.952 +    } else {
   1.953 +        // see if JS code signaled failure result without throwing exception
   1.954 +        if (NS_FAILED(pending_result)) {
   1.955 +            return pending_result;
   1.956 +        }
   1.957 +    }
   1.958 +    return NS_ERROR_FAILURE;
   1.959 +}
   1.960 +
   1.961 +NS_IMETHODIMP
   1.962 +nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
   1.963 +                                const XPTMethodDescriptor* info_,
   1.964 +                                nsXPTCMiniVariant* nativeParams)
   1.965 +{
   1.966 +    jsval* sp = nullptr;
   1.967 +    jsval* argv = nullptr;
   1.968 +    uint8_t i;
   1.969 +    nsresult retval = NS_ERROR_FAILURE;
   1.970 +    nsresult pending_result = NS_OK;
   1.971 +    bool success;
   1.972 +    bool readyToDoTheCall = false;
   1.973 +    nsID  param_iid;
   1.974 +    const nsXPTMethodInfo* info = static_cast<const nsXPTMethodInfo*>(info_);
   1.975 +    const char* name = info->name;
   1.976 +    bool foundDependentParam;
   1.977 +
   1.978 +    // Make sure not to set the callee on ccx until after we've gone through
   1.979 +    // the whole nsIXPCFunctionThisTranslator bit.  That code uses ccx to
   1.980 +    // convert natives to JSObjects, but we do NOT plan to pass those JSObjects
   1.981 +    // to our real callee.
   1.982 +    AutoPushJSContext context(GetContextFromObjectOrDefault(wrapper));
   1.983 +    XPCCallContext ccx(NATIVE_CALLER, context);
   1.984 +    if (!ccx.IsValid())
   1.985 +        return retval;
   1.986 +
   1.987 +    XPCContext *xpcc = ccx.GetXPCContext();
   1.988 +    JSContext *cx = ccx.GetJSContext();
   1.989 +
   1.990 +    if (!cx || !xpcc || !IsReflectable(methodIndex))
   1.991 +        return NS_ERROR_FAILURE;
   1.992 +
   1.993 +    // [implicit_jscontext] and [optional_argc] have a different calling
   1.994 +    // convention, which we don't support for JS-implemented components.
   1.995 +    if (info->WantsOptArgc() || info->WantsContext()) {
   1.996 +        const char *str = "IDL methods marked with [implicit_jscontext] "
   1.997 +                          "or [optional_argc] may not be implemented in JS";
   1.998 +        // Throw and warn for good measure.
   1.999 +        JS_ReportError(cx, str);
  1.1000 +        NS_WARNING(str);
  1.1001 +        return NS_ERROR_FAILURE;
  1.1002 +    }
  1.1003 +
  1.1004 +    RootedValue fval(cx);
  1.1005 +    RootedObject obj(cx, wrapper->GetJSObject());
  1.1006 +    RootedObject thisObj(cx, obj);
  1.1007 +
  1.1008 +    JSAutoCompartment ac(cx, obj);
  1.1009 +
  1.1010 +    AutoValueVector args(cx);
  1.1011 +    AutoScriptEvaluate scriptEval(cx);
  1.1012 +
  1.1013 +    // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
  1.1014 +    uint8_t paramCount = info->num_args;
  1.1015 +    uint8_t argc = paramCount -
  1.1016 +        (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
  1.1017 +
  1.1018 +    if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter))
  1.1019 +        goto pre_call_clean_up;
  1.1020 +
  1.1021 +    xpcc->SetPendingResult(pending_result);
  1.1022 +    xpcc->SetException(nullptr);
  1.1023 +    XPCJSRuntime::Get()->SetPendingException(nullptr);
  1.1024 +
  1.1025 +    // We use js_Invoke so that the gcthings we use as args will be rooted by
  1.1026 +    // the engine as we do conversions and prepare to do the function call.
  1.1027 +
  1.1028 +    // setup stack
  1.1029 +
  1.1030 +    // if this isn't a function call then we don't need to push extra stuff
  1.1031 +    if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) {
  1.1032 +        // We get fval before allocating the stack to avoid gc badness that can
  1.1033 +        // happen if the GetProperty call leaves our request and the gc runs
  1.1034 +        // while the stack we allocate contains garbage.
  1.1035 +
  1.1036 +        // If the interface is marked as a [function] then we will assume that
  1.1037 +        // our JSObject is a function and not an object with a named method.
  1.1038 +
  1.1039 +        bool isFunction;
  1.1040 +        if (NS_FAILED(mInfo->IsFunction(&isFunction)))
  1.1041 +            goto pre_call_clean_up;
  1.1042 +
  1.1043 +        // In the xpidl [function] case we are making sure now that the
  1.1044 +        // JSObject is callable. If it is *not* callable then we silently
  1.1045 +        // fallback to looking up the named property...
  1.1046 +        // (because jst says he thinks this fallback is 'The Right Thing'.)
  1.1047 +        //
  1.1048 +        // In the normal (non-function) case we just lookup the property by
  1.1049 +        // name and as long as the object has such a named property we go ahead
  1.1050 +        // and try to make the call. If it turns out the named property is not
  1.1051 +        // a callable object then the JS engine will throw an error and we'll
  1.1052 +        // pass this along to the caller as an exception/result code.
  1.1053 +
  1.1054 +        fval = ObjectValue(*obj);
  1.1055 +        if (isFunction &&
  1.1056 +            JS_TypeOfValue(ccx, fval) == JSTYPE_FUNCTION) {
  1.1057 +
  1.1058 +            // We may need to translate the 'this' for the function object.
  1.1059 +
  1.1060 +            if (paramCount) {
  1.1061 +                const nsXPTParamInfo& firstParam = info->params[0];
  1.1062 +                if (firstParam.IsIn()) {
  1.1063 +                    const nsXPTType& firstType = firstParam.GetType();
  1.1064 +
  1.1065 +                    if (firstType.IsInterfacePointer()) {
  1.1066 +                        nsIXPCFunctionThisTranslator* translator;
  1.1067 +
  1.1068 +                        IID2ThisTranslatorMap* map =
  1.1069 +                            mRuntime->GetThisTranslatorMap();
  1.1070 +
  1.1071 +                        translator = map->Find(mIID);
  1.1072 +
  1.1073 +                        if (translator) {
  1.1074 +                            nsCOMPtr<nsISupports> newThis;
  1.1075 +                            if (NS_FAILED(translator->
  1.1076 +                                          TranslateThis((nsISupports*)nativeParams[0].val.p,
  1.1077 +                                                        getter_AddRefs(newThis)))) {
  1.1078 +                                goto pre_call_clean_up;
  1.1079 +                            }
  1.1080 +                            if (newThis) {
  1.1081 +                                RootedValue v(cx);
  1.1082 +                                xpcObjectHelper helper(newThis);
  1.1083 +                                bool ok =
  1.1084 +                                  XPCConvert::NativeInterface2JSObject(
  1.1085 +                                      &v, nullptr, helper, nullptr,
  1.1086 +                                      nullptr, false, nullptr);
  1.1087 +                                if (!ok) {
  1.1088 +                                    goto pre_call_clean_up;
  1.1089 +                                }
  1.1090 +                                thisObj = JSVAL_TO_OBJECT(v);
  1.1091 +                                if (!JS_WrapObject(cx, &thisObj))
  1.1092 +                                    goto pre_call_clean_up;
  1.1093 +                            }
  1.1094 +                        }
  1.1095 +                    }
  1.1096 +                }
  1.1097 +            }
  1.1098 +        } else {
  1.1099 +            if (!JS_GetProperty(cx, obj, name, &fval))
  1.1100 +                goto pre_call_clean_up;
  1.1101 +            // XXX We really want to factor out the error reporting better and
  1.1102 +            // specifically report the failure to find a function with this name.
  1.1103 +            // This is what we do below if the property is found but is not a
  1.1104 +            // function. We just need to factor better so we can get to that
  1.1105 +            // reporting path from here.
  1.1106 +
  1.1107 +            thisObj = obj;
  1.1108 +        }
  1.1109 +    }
  1.1110 +
  1.1111 +    if (!args.resize(argc)) {
  1.1112 +        retval = NS_ERROR_OUT_OF_MEMORY;
  1.1113 +        goto pre_call_clean_up;
  1.1114 +    }
  1.1115 +
  1.1116 +    argv = args.begin();
  1.1117 +    sp = argv;
  1.1118 +
  1.1119 +    // build the args
  1.1120 +    // NB: This assignment *looks* wrong because we haven't yet called our
  1.1121 +    // function. However, we *have* already entered the compartmen that we're
  1.1122 +    // about to call, and that's the global that we want here. In other words:
  1.1123 +    // we're trusting the JS engine to come up with a good global to use for
  1.1124 +    // our object (whatever it was).
  1.1125 +    for (i = 0; i < argc; i++) {
  1.1126 +        const nsXPTParamInfo& param = info->params[i];
  1.1127 +        const nsXPTType& type = param.GetType();
  1.1128 +        nsXPTType datum_type;
  1.1129 +        uint32_t array_count;
  1.1130 +        bool isArray = type.IsArray();
  1.1131 +        RootedValue val(cx, NullValue());
  1.1132 +        bool isSizedString = isArray ?
  1.1133 +                false :
  1.1134 +                type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
  1.1135 +                type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
  1.1136 +
  1.1137 +
  1.1138 +        // verify that null was not passed for 'out' param
  1.1139 +        if (param.IsOut() && !nativeParams[i].val.p) {
  1.1140 +            retval = NS_ERROR_INVALID_ARG;
  1.1141 +            goto pre_call_clean_up;
  1.1142 +        }
  1.1143 +
  1.1144 +        if (isArray) {
  1.1145 +            if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
  1.1146 +                                                 &datum_type)))
  1.1147 +                goto pre_call_clean_up;
  1.1148 +        } else
  1.1149 +            datum_type = type;
  1.1150 +
  1.1151 +        if (param.IsIn()) {
  1.1152 +            nsXPTCMiniVariant* pv;
  1.1153 +
  1.1154 +            if (param.IsIndirect())
  1.1155 +                pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
  1.1156 +            else
  1.1157 +                pv = &nativeParams[i];
  1.1158 +
  1.1159 +            if (datum_type.IsInterfacePointer() &&
  1.1160 +                !GetInterfaceTypeFromParam(cx, info, param, methodIndex,
  1.1161 +                                           datum_type, nativeParams,
  1.1162 +                                           &param_iid))
  1.1163 +                goto pre_call_clean_up;
  1.1164 +
  1.1165 +            if (isArray || isSizedString) {
  1.1166 +                if (!GetArraySizeFromParam(cx, info, param, methodIndex,
  1.1167 +                                           i, nativeParams, &array_count))
  1.1168 +                    goto pre_call_clean_up;
  1.1169 +            }
  1.1170 +
  1.1171 +            if (isArray) {
  1.1172 +                if (!XPCConvert::NativeArray2JS(&val,
  1.1173 +                                                (const void**)&pv->val,
  1.1174 +                                                datum_type, &param_iid,
  1.1175 +                                                array_count, nullptr))
  1.1176 +                    goto pre_call_clean_up;
  1.1177 +            } else if (isSizedString) {
  1.1178 +                if (!XPCConvert::NativeStringWithSize2JS(&val,
  1.1179 +                                                         (const void*)&pv->val,
  1.1180 +                                                         datum_type,
  1.1181 +                                                         array_count, nullptr))
  1.1182 +                    goto pre_call_clean_up;
  1.1183 +            } else {
  1.1184 +                if (!XPCConvert::NativeData2JS(&val, &pv->val, type,
  1.1185 +                                               &param_iid, nullptr))
  1.1186 +                    goto pre_call_clean_up;
  1.1187 +            }
  1.1188 +        }
  1.1189 +
  1.1190 +        if (param.IsOut() || param.IsDipper()) {
  1.1191 +            // create an 'out' object
  1.1192 +            RootedObject out_obj(cx, NewOutObject(cx, obj));
  1.1193 +            if (!out_obj) {
  1.1194 +                retval = NS_ERROR_OUT_OF_MEMORY;
  1.1195 +                goto pre_call_clean_up;
  1.1196 +            }
  1.1197 +
  1.1198 +            if (param.IsIn()) {
  1.1199 +                if (!JS_SetPropertyById(cx, out_obj,
  1.1200 +                                        mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
  1.1201 +                                        val)) {
  1.1202 +                    goto pre_call_clean_up;
  1.1203 +                }
  1.1204 +            }
  1.1205 +            *sp++ = OBJECT_TO_JSVAL(out_obj);
  1.1206 +        } else
  1.1207 +            *sp++ = val;
  1.1208 +    }
  1.1209 +
  1.1210 +    readyToDoTheCall = true;
  1.1211 +
  1.1212 +pre_call_clean_up:
  1.1213 +    // clean up any 'out' params handed in
  1.1214 +    for (i = 0; i < paramCount; i++) {
  1.1215 +        const nsXPTParamInfo& param = info->params[i];
  1.1216 +        if (!param.IsOut())
  1.1217 +            continue;
  1.1218 +
  1.1219 +        const nsXPTType& type = param.GetType();
  1.1220 +        if (!type.deprecated_IsPointer())
  1.1221 +            continue;
  1.1222 +        void* p;
  1.1223 +        if (!(p = nativeParams[i].val.p))
  1.1224 +            continue;
  1.1225 +
  1.1226 +        if (param.IsIn()) {
  1.1227 +            if (type.IsArray()) {
  1.1228 +                void** pp;
  1.1229 +                if (nullptr != (pp = *((void***)p))) {
  1.1230 +
  1.1231 +                    // we need to get the array length and iterate the items
  1.1232 +                    uint32_t array_count;
  1.1233 +                    nsXPTType datum_type;
  1.1234 +
  1.1235 +                    if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
  1.1236 +                                                            1, &datum_type)) &&
  1.1237 +                        datum_type.deprecated_IsPointer() &&
  1.1238 +                        GetArraySizeFromParam(cx, info, param, methodIndex,
  1.1239 +                                              i, nativeParams, &array_count) &&
  1.1240 +                        array_count) {
  1.1241 +
  1.1242 +                        CleanupPointerArray(datum_type, array_count, pp);
  1.1243 +                    }
  1.1244 +
  1.1245 +                    // always release the array if it is inout
  1.1246 +                    nsMemory::Free(pp);
  1.1247 +                }
  1.1248 +            } else
  1.1249 +                CleanupPointerTypeObject(type, (void**)p);
  1.1250 +        }
  1.1251 +        *((void**)p) = nullptr;
  1.1252 +    }
  1.1253 +
  1.1254 +    // Make sure "this" doesn't get deleted during this call.
  1.1255 +    nsCOMPtr<nsIXPCWrappedJSClass> kungFuDeathGrip(this);
  1.1256 +
  1.1257 +    if (!readyToDoTheCall)
  1.1258 +        return retval;
  1.1259 +
  1.1260 +    // do the deed - note exceptions
  1.1261 +
  1.1262 +    JS_ClearPendingException(cx);
  1.1263 +
  1.1264 +    RootedValue rval(cx);
  1.1265 +    if (XPT_MD_IS_GETTER(info->flags)) {
  1.1266 +        success = JS_GetProperty(cx, obj, name, &rval);
  1.1267 +    } else if (XPT_MD_IS_SETTER(info->flags)) {
  1.1268 +        rval = *argv;
  1.1269 +        success = JS_SetProperty(cx, obj, name, rval);
  1.1270 +    } else {
  1.1271 +        if (!JSVAL_IS_PRIMITIVE(fval)) {
  1.1272 +            AutoSaveContextOptions asco(cx);
  1.1273 +            ContextOptionsRef(cx).setDontReportUncaught(true);
  1.1274 +
  1.1275 +            success = JS_CallFunctionValue(cx, thisObj, fval, args, &rval);
  1.1276 +        } else {
  1.1277 +            // The property was not an object so can't be a function.
  1.1278 +            // Let's build and 'throw' an exception.
  1.1279 +
  1.1280 +            static const nsresult code =
  1.1281 +                    NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
  1.1282 +            static const char format[] = "%s \"%s\"";
  1.1283 +            const char * msg;
  1.1284 +            char* sz = nullptr;
  1.1285 +
  1.1286 +            if (nsXPCException::NameAndFormatForNSResult(code, nullptr, &msg) && msg)
  1.1287 +                sz = JS_smprintf(format, msg, name);
  1.1288 +
  1.1289 +            nsCOMPtr<nsIException> e;
  1.1290 +
  1.1291 +            XPCConvert::ConstructException(code, sz, GetInterfaceName(), name,
  1.1292 +                                           nullptr, getter_AddRefs(e), nullptr, nullptr);
  1.1293 +            xpcc->SetException(e);
  1.1294 +            if (sz)
  1.1295 +                JS_smprintf_free(sz);
  1.1296 +            success = false;
  1.1297 +        }
  1.1298 +    }
  1.1299 +
  1.1300 +    if (!success) {
  1.1301 +        bool forceReport;
  1.1302 +        if (NS_FAILED(mInfo->IsFunction(&forceReport)))
  1.1303 +            forceReport = false;
  1.1304 +
  1.1305 +        // May also want to check if we're moving from content->chrome and force
  1.1306 +        // a report in that case.
  1.1307 +
  1.1308 +        return CheckForException(ccx, name, GetInterfaceName(), forceReport);
  1.1309 +    }
  1.1310 +
  1.1311 +    XPCJSRuntime::Get()->SetPendingException(nullptr); // XXX necessary?
  1.1312 +
  1.1313 +    // convert out args and result
  1.1314 +    // NOTE: this is the total number of native params, not just the args
  1.1315 +    // Convert independent params only.
  1.1316 +    // When we later convert the dependent params (if any) we will know that
  1.1317 +    // the params upon which they depend will have already been converted -
  1.1318 +    // regardless of ordering.
  1.1319 +
  1.1320 +    foundDependentParam = false;
  1.1321 +    for (i = 0; i < paramCount; i++) {
  1.1322 +        const nsXPTParamInfo& param = info->params[i];
  1.1323 +        MOZ_ASSERT(!param.IsShared(), "[shared] implies [noscript]!");
  1.1324 +        if (!param.IsOut() && !param.IsDipper())
  1.1325 +            continue;
  1.1326 +
  1.1327 +        const nsXPTType& type = param.GetType();
  1.1328 +        if (type.IsDependent()) {
  1.1329 +            foundDependentParam = true;
  1.1330 +            continue;
  1.1331 +        }
  1.1332 +
  1.1333 +        RootedValue val(cx);
  1.1334 +        uint8_t type_tag = type.TagPart();
  1.1335 +        nsXPTCMiniVariant* pv;
  1.1336 +
  1.1337 +        if (param.IsDipper())
  1.1338 +            pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p;
  1.1339 +        else
  1.1340 +            pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
  1.1341 +
  1.1342 +        if (param.IsRetval())
  1.1343 +            val = rval;
  1.1344 +        else if (argv[i].isPrimitive())
  1.1345 +            break;
  1.1346 +        else {
  1.1347 +            RootedObject obj(cx, &argv[i].toObject());
  1.1348 +            if (!JS_GetPropertyById(cx, obj,
  1.1349 +                                    mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
  1.1350 +                                    &val))
  1.1351 +                break;
  1.1352 +        }
  1.1353 +
  1.1354 +        // setup allocator and/or iid
  1.1355 +
  1.1356 +        if (type_tag == nsXPTType::T_INTERFACE) {
  1.1357 +            if (NS_FAILED(GetInterfaceInfo()->
  1.1358 +                          GetIIDForParamNoAlloc(methodIndex, &param,
  1.1359 +                                                &param_iid)))
  1.1360 +                break;
  1.1361 +        }
  1.1362 +
  1.1363 +// see bug #961488
  1.1364 +#if (defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(_AIX)) && \
  1.1365 +    ((defined(__sparc) && !defined(__sparcv9) && !defined(__sparcv9__)) || \
  1.1366 +    (defined(__powerpc__) && !defined (__powerpc64__)))
  1.1367 +        if (type_tag == nsXPTType::T_JSVAL) {
  1.1368 +            if (!XPCConvert::JSData2Native(*(void**)(&pv->val), val, type,
  1.1369 +                                           !param.IsDipper(), &param_iid, nullptr))
  1.1370 +                break;
  1.1371 +        } else
  1.1372 +#endif
  1.1373 +        {
  1.1374 +            if (!XPCConvert::JSData2Native(&pv->val, val, type,
  1.1375 +                                           !param.IsDipper(), &param_iid, nullptr))
  1.1376 +                break;
  1.1377 +        }
  1.1378 +    }
  1.1379 +
  1.1380 +    // if any params were dependent, then we must iterate again to convert them.
  1.1381 +    if (foundDependentParam && i == paramCount) {
  1.1382 +        for (i = 0; i < paramCount; i++) {
  1.1383 +            const nsXPTParamInfo& param = info->params[i];
  1.1384 +            if (!param.IsOut())
  1.1385 +                continue;
  1.1386 +
  1.1387 +            const nsXPTType& type = param.GetType();
  1.1388 +            if (!type.IsDependent())
  1.1389 +                continue;
  1.1390 +
  1.1391 +            RootedValue val(cx);
  1.1392 +            nsXPTCMiniVariant* pv;
  1.1393 +            nsXPTType datum_type;
  1.1394 +            uint32_t array_count;
  1.1395 +            bool isArray = type.IsArray();
  1.1396 +            bool isSizedString = isArray ?
  1.1397 +                    false :
  1.1398 +                    type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
  1.1399 +                    type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
  1.1400 +
  1.1401 +            pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
  1.1402 +
  1.1403 +            if (param.IsRetval())
  1.1404 +                val = rval;
  1.1405 +            else {
  1.1406 +                RootedObject obj(cx, &argv[i].toObject());
  1.1407 +                if (!JS_GetPropertyById(cx, obj,
  1.1408 +                                        mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
  1.1409 +                                        &val))
  1.1410 +                    break;
  1.1411 +            }
  1.1412 +
  1.1413 +            // setup allocator and/or iid
  1.1414 +
  1.1415 +            if (isArray) {
  1.1416 +                if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
  1.1417 +                                                     &datum_type)))
  1.1418 +                    break;
  1.1419 +            } else
  1.1420 +                datum_type = type;
  1.1421 +
  1.1422 +            if (datum_type.IsInterfacePointer()) {
  1.1423 +               if (!GetInterfaceTypeFromParam(cx, info, param, methodIndex,
  1.1424 +                                              datum_type, nativeParams,
  1.1425 +                                              &param_iid))
  1.1426 +                   break;
  1.1427 +            }
  1.1428 +
  1.1429 +            if (isArray || isSizedString) {
  1.1430 +                if (!GetArraySizeFromParam(cx, info, param, methodIndex,
  1.1431 +                                           i, nativeParams, &array_count))
  1.1432 +                    break;
  1.1433 +            }
  1.1434 +
  1.1435 +            if (isArray) {
  1.1436 +                if (array_count &&
  1.1437 +                    !XPCConvert::JSArray2Native((void**)&pv->val, val,
  1.1438 +                                                array_count, datum_type,
  1.1439 +                                                &param_iid, nullptr))
  1.1440 +                    break;
  1.1441 +            } else if (isSizedString) {
  1.1442 +                if (!XPCConvert::JSStringWithSize2Native((void*)&pv->val, val,
  1.1443 +                                                         array_count, datum_type,
  1.1444 +                                                         nullptr))
  1.1445 +                    break;
  1.1446 +            } else {
  1.1447 +                if (!XPCConvert::JSData2Native(&pv->val, val, type,
  1.1448 +                                               true, &param_iid,
  1.1449 +                                               nullptr))
  1.1450 +                    break;
  1.1451 +            }
  1.1452 +        }
  1.1453 +    }
  1.1454 +
  1.1455 +    if (i != paramCount) {
  1.1456 +        // We didn't manage all the result conversions!
  1.1457 +        // We have to cleanup any junk that *did* get converted.
  1.1458 +
  1.1459 +        for (uint8_t k = 0; k < i; k++) {
  1.1460 +            const nsXPTParamInfo& param = info->params[k];
  1.1461 +            if (!param.IsOut())
  1.1462 +                continue;
  1.1463 +            const nsXPTType& type = param.GetType();
  1.1464 +            if (!type.deprecated_IsPointer())
  1.1465 +                continue;
  1.1466 +            void* p;
  1.1467 +            if (!(p = nativeParams[k].val.p))
  1.1468 +                continue;
  1.1469 +
  1.1470 +            if (type.IsArray()) {
  1.1471 +                void** pp;
  1.1472 +                if (nullptr != (pp = *((void***)p))) {
  1.1473 +                    // we need to get the array length and iterate the items
  1.1474 +                    uint32_t array_count;
  1.1475 +                    nsXPTType datum_type;
  1.1476 +
  1.1477 +                    if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
  1.1478 +                                                            1, &datum_type)) &&
  1.1479 +                        datum_type.deprecated_IsPointer() &&
  1.1480 +                        GetArraySizeFromParam(cx, info, param, methodIndex,
  1.1481 +                                              k, nativeParams, &array_count) &&
  1.1482 +                        array_count) {
  1.1483 +
  1.1484 +                        CleanupPointerArray(datum_type, array_count, pp);
  1.1485 +                    }
  1.1486 +                    nsMemory::Free(pp);
  1.1487 +                }
  1.1488 +            } else
  1.1489 +                CleanupPointerTypeObject(type, (void**)p);
  1.1490 +            *((void**)p) = nullptr;
  1.1491 +        }
  1.1492 +    } else {
  1.1493 +        // set to whatever the JS code might have set as the result
  1.1494 +        retval = pending_result;
  1.1495 +    }
  1.1496 +
  1.1497 +    return retval;
  1.1498 +}
  1.1499 +
  1.1500 +const char*
  1.1501 +nsXPCWrappedJSClass::GetInterfaceName()
  1.1502 +{
  1.1503 +    if (!mName)
  1.1504 +        mInfo->GetName(&mName);
  1.1505 +    return mName;
  1.1506 +}
  1.1507 +
  1.1508 +static void
  1.1509 +FinalizeStub(JSFreeOp *fop, JSObject *obj)
  1.1510 +{
  1.1511 +}
  1.1512 +
  1.1513 +static const JSClass XPCOutParamClass = {
  1.1514 +    "XPCOutParam",
  1.1515 +    0,
  1.1516 +    JS_PropertyStub,
  1.1517 +    JS_DeletePropertyStub,
  1.1518 +    JS_PropertyStub,
  1.1519 +    JS_StrictPropertyStub,
  1.1520 +    JS_EnumerateStub,
  1.1521 +    JS_ResolveStub,
  1.1522 +    JS_ConvertStub,
  1.1523 +    FinalizeStub,
  1.1524 +    nullptr,   /* call */
  1.1525 +    nullptr,   /* hasInstance */
  1.1526 +    nullptr,   /* construct */
  1.1527 +    nullptr    /* trace */
  1.1528 +};
  1.1529 +
  1.1530 +bool
  1.1531 +xpc::IsOutObject(JSContext* cx, JSObject* obj)
  1.1532 +{
  1.1533 +    return js::GetObjectJSClass(obj) == &XPCOutParamClass;
  1.1534 +}
  1.1535 +
  1.1536 +JSObject*
  1.1537 +xpc::NewOutObject(JSContext* cx, JSObject* scope)
  1.1538 +{
  1.1539 +    RootedObject global(cx, JS_GetGlobalForObject(cx, scope));
  1.1540 +    return JS_NewObject(cx, nullptr, NullPtr(), global);
  1.1541 +}
  1.1542 +
  1.1543 +
  1.1544 +NS_IMETHODIMP
  1.1545 +nsXPCWrappedJSClass::DebugDump(int16_t depth)
  1.1546 +{
  1.1547 +#ifdef DEBUG
  1.1548 +    depth-- ;
  1.1549 +    XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %x with mRefCnt = %d", this, mRefCnt.get()));
  1.1550 +    XPC_LOG_INDENT();
  1.1551 +        char* name;
  1.1552 +        mInfo->GetName(&name);
  1.1553 +        XPC_LOG_ALWAYS(("interface name is %s", name));
  1.1554 +        if (name)
  1.1555 +            nsMemory::Free(name);
  1.1556 +        char * iid = mIID.ToString();
  1.1557 +        XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
  1.1558 +        if (iid)
  1.1559 +            NS_Free(iid);
  1.1560 +        XPC_LOG_ALWAYS(("InterfaceInfo @ %x", mInfo.get()));
  1.1561 +        uint16_t methodCount = 0;
  1.1562 +        if (depth) {
  1.1563 +            uint16_t i;
  1.1564 +            nsCOMPtr<nsIInterfaceInfo> parent;
  1.1565 +            XPC_LOG_INDENT();
  1.1566 +            mInfo->GetParent(getter_AddRefs(parent));
  1.1567 +            XPC_LOG_ALWAYS(("parent @ %x", parent.get()));
  1.1568 +            mInfo->GetMethodCount(&methodCount);
  1.1569 +            XPC_LOG_ALWAYS(("MethodCount = %d", methodCount));
  1.1570 +            mInfo->GetConstantCount(&i);
  1.1571 +            XPC_LOG_ALWAYS(("ConstantCount = %d", i));
  1.1572 +            XPC_LOG_OUTDENT();
  1.1573 +        }
  1.1574 +        XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
  1.1575 +        XPC_LOG_ALWAYS(("mDescriptors @ %x count = %d", mDescriptors, methodCount));
  1.1576 +        if (depth && mDescriptors && methodCount) {
  1.1577 +            depth--;
  1.1578 +            XPC_LOG_INDENT();
  1.1579 +            for (uint16_t i = 0; i < methodCount; i++) {
  1.1580 +                XPC_LOG_ALWAYS(("Method %d is %s%s", \
  1.1581 +                                i, IsReflectable(i) ? "":" NOT ","reflectable"));
  1.1582 +            }
  1.1583 +            XPC_LOG_OUTDENT();
  1.1584 +            depth++;
  1.1585 +        }
  1.1586 +    XPC_LOG_OUTDENT();
  1.1587 +#endif
  1.1588 +    return NS_OK;
  1.1589 +}

mercurial