js/xpconnect/src/XPCWrappedJSClass.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* Sharable code and data for wrapper around JSObjects. */
michael@0 8
michael@0 9 #include "xpcprivate.h"
michael@0 10 #include "jsprf.h"
michael@0 11 #include "nsArrayEnumerator.h"
michael@0 12 #include "nsContentUtils.h"
michael@0 13 #include "nsWrapperCache.h"
michael@0 14 #include "AccessCheck.h"
michael@0 15 #include "nsJSUtils.h"
michael@0 16 #include "mozilla/Attributes.h"
michael@0 17 #include "mozilla/dom/BindingUtils.h"
michael@0 18 #include "mozilla/dom/DOMException.h"
michael@0 19 #include "mozilla/dom/DOMExceptionBinding.h"
michael@0 20
michael@0 21 #include "jsapi.h"
michael@0 22 #include "jsfriendapi.h"
michael@0 23
michael@0 24 using namespace xpc;
michael@0 25 using namespace JS;
michael@0 26 using namespace mozilla;
michael@0 27
michael@0 28 NS_IMPL_ISUPPORTS(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
michael@0 29
michael@0 30 // the value of this variable is never used - we use its address as a sentinel
michael@0 31 static uint32_t zero_methods_descriptor;
michael@0 32
michael@0 33 bool AutoScriptEvaluate::StartEvaluating(HandleObject scope, JSErrorReporter errorReporter)
michael@0 34 {
michael@0 35 NS_PRECONDITION(!mEvaluated, "AutoScriptEvaluate::Evaluate should only be called once");
michael@0 36
michael@0 37 if (!mJSContext)
michael@0 38 return true;
michael@0 39
michael@0 40 mEvaluated = true;
michael@0 41 if (!JS_GetErrorReporter(mJSContext)) {
michael@0 42 JS_SetErrorReporter(mJSContext, errorReporter);
michael@0 43 mErrorReporterSet = true;
michael@0 44 }
michael@0 45
michael@0 46 JS_BeginRequest(mJSContext);
michael@0 47 mAutoCompartment.construct(mJSContext, scope);
michael@0 48
michael@0 49 // Saving the exception state keeps us from interfering with another script
michael@0 50 // that may also be running on this context. This occurred first with the
michael@0 51 // js debugger, as described in
michael@0 52 // http://bugzilla.mozilla.org/show_bug.cgi?id=88130 but presumably could
michael@0 53 // show up in any situation where a script calls into a wrapped js component
michael@0 54 // on the same context, while the context has a nonzero exception state.
michael@0 55 mState.construct(mJSContext);
michael@0 56
michael@0 57 return true;
michael@0 58 }
michael@0 59
michael@0 60 AutoScriptEvaluate::~AutoScriptEvaluate()
michael@0 61 {
michael@0 62 if (!mJSContext || !mEvaluated)
michael@0 63 return;
michael@0 64 mState.ref().restore();
michael@0 65
michael@0 66 JS_EndRequest(mJSContext);
michael@0 67
michael@0 68 if (mErrorReporterSet)
michael@0 69 JS_SetErrorReporter(mJSContext, nullptr);
michael@0 70 }
michael@0 71
michael@0 72 // It turns out that some errors may be not worth reporting. So, this
michael@0 73 // function is factored out to manage that.
michael@0 74 bool xpc_IsReportableErrorCode(nsresult code)
michael@0 75 {
michael@0 76 if (NS_SUCCEEDED(code))
michael@0 77 return false;
michael@0 78
michael@0 79 switch (code) {
michael@0 80 // Error codes that we don't want to report as errors...
michael@0 81 // These generally indicate bad interface design AFAIC.
michael@0 82 case NS_ERROR_FACTORY_REGISTER_AGAIN:
michael@0 83 case NS_BASE_STREAM_WOULD_BLOCK:
michael@0 84 return false;
michael@0 85 default:
michael@0 86 return true;
michael@0 87 }
michael@0 88 }
michael@0 89
michael@0 90 // static
michael@0 91 already_AddRefed<nsXPCWrappedJSClass>
michael@0 92 nsXPCWrappedJSClass::GetNewOrUsed(JSContext* cx, REFNSIID aIID)
michael@0 93 {
michael@0 94 XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
michael@0 95 IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
michael@0 96 nsRefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
michael@0 97
michael@0 98 if (!clasp) {
michael@0 99 nsCOMPtr<nsIInterfaceInfo> info;
michael@0 100 nsXPConnect::XPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
michael@0 101 if (info) {
michael@0 102 bool canScript, isBuiltin;
michael@0 103 if (NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
michael@0 104 NS_SUCCEEDED(info->IsBuiltinClass(&isBuiltin)) && !isBuiltin &&
michael@0 105 nsXPConnect::IsISupportsDescendant(info))
michael@0 106 {
michael@0 107 clasp = new nsXPCWrappedJSClass(cx, aIID, info);
michael@0 108 if (!clasp->mDescriptors)
michael@0 109 clasp = nullptr;
michael@0 110 }
michael@0 111 }
michael@0 112 }
michael@0 113 return clasp.forget();
michael@0 114 }
michael@0 115
michael@0 116 nsXPCWrappedJSClass::nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
michael@0 117 nsIInterfaceInfo* aInfo)
michael@0 118 : mRuntime(nsXPConnect::GetRuntimeInstance()),
michael@0 119 mInfo(aInfo),
michael@0 120 mName(nullptr),
michael@0 121 mIID(aIID),
michael@0 122 mDescriptors(nullptr)
michael@0 123 {
michael@0 124 mRuntime->GetWrappedJSClassMap()->Add(this);
michael@0 125
michael@0 126 uint16_t methodCount;
michael@0 127 if (NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) {
michael@0 128 if (methodCount) {
michael@0 129 int wordCount = (methodCount/32)+1;
michael@0 130 if (nullptr != (mDescriptors = new uint32_t[wordCount])) {
michael@0 131 int i;
michael@0 132 // init flags to 0;
michael@0 133 for (i = wordCount-1; i >= 0; i--)
michael@0 134 mDescriptors[i] = 0;
michael@0 135
michael@0 136 for (i = 0; i < methodCount; i++) {
michael@0 137 const nsXPTMethodInfo* info;
michael@0 138 if (NS_SUCCEEDED(mInfo->GetMethodInfo(i, &info)))
michael@0 139 SetReflectable(i, XPCConvert::IsMethodReflectable(*info));
michael@0 140 else {
michael@0 141 delete [] mDescriptors;
michael@0 142 mDescriptors = nullptr;
michael@0 143 break;
michael@0 144 }
michael@0 145 }
michael@0 146 }
michael@0 147 } else {
michael@0 148 mDescriptors = &zero_methods_descriptor;
michael@0 149 }
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 nsXPCWrappedJSClass::~nsXPCWrappedJSClass()
michael@0 154 {
michael@0 155 if (mDescriptors && mDescriptors != &zero_methods_descriptor)
michael@0 156 delete [] mDescriptors;
michael@0 157 if (mRuntime)
michael@0 158 mRuntime->GetWrappedJSClassMap()->Remove(this);
michael@0 159
michael@0 160 if (mName)
michael@0 161 nsMemory::Free(mName);
michael@0 162 }
michael@0 163
michael@0 164 JSObject*
michael@0 165 nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
michael@0 166 JSObject* jsobjArg,
michael@0 167 REFNSIID aIID)
michael@0 168 {
michael@0 169 RootedObject jsobj(cx, jsobjArg);
michael@0 170 JSObject* id;
michael@0 171 RootedValue retval(cx);
michael@0 172 RootedObject retObj(cx);
michael@0 173 bool success = false;
michael@0 174 RootedValue fun(cx);
michael@0 175
michael@0 176 // Don't call the actual function on a content object. We'll determine
michael@0 177 // whether or not a content object is capable of implementing the
michael@0 178 // interface (i.e. whether the interface is scriptable) and most content
michael@0 179 // objects don't have QI implementations anyway. Also see bug 503926.
michael@0 180 if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(jsobj))) {
michael@0 181 return nullptr;
michael@0 182 }
michael@0 183
michael@0 184 // OK, it looks like we'll be calling into JS code.
michael@0 185 AutoScriptEvaluate scriptEval(cx);
michael@0 186
michael@0 187 // XXX we should install an error reporter that will send reports to
michael@0 188 // the JS error console service.
michael@0 189 if (!scriptEval.StartEvaluating(jsobj))
michael@0 190 return nullptr;
michael@0 191
michael@0 192 // check upfront for the existence of the function property
michael@0 193 HandleId funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
michael@0 194 if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
michael@0 195 return nullptr;
michael@0 196
michael@0 197 // Ensure that we are asking for a scriptable interface.
michael@0 198 // NB: It's important for security that this check is here rather
michael@0 199 // than later, since it prevents untrusted objects from implementing
michael@0 200 // some interfaces in JS and aggregating a trusted object to
michael@0 201 // implement intentionally (for security) unscriptable interfaces.
michael@0 202 // We so often ask for nsISupports that we can short-circuit the test...
michael@0 203 if (!aIID.Equals(NS_GET_IID(nsISupports))) {
michael@0 204 nsCOMPtr<nsIInterfaceInfo> info;
michael@0 205 nsXPConnect::XPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
michael@0 206 if (!info)
michael@0 207 return nullptr;
michael@0 208 bool canScript, isBuiltin;
michael@0 209 if (NS_FAILED(info->IsScriptable(&canScript)) || !canScript ||
michael@0 210 NS_FAILED(info->IsBuiltinClass(&isBuiltin)) || isBuiltin)
michael@0 211 return nullptr;
michael@0 212 }
michael@0 213
michael@0 214 id = xpc_NewIDObject(cx, jsobj, aIID);
michael@0 215 if (id) {
michael@0 216 // Throwing NS_NOINTERFACE is the prescribed way to fail QI from JS. It
michael@0 217 // is not an exception that is ever worth reporting, but we don't want
michael@0 218 // to eat all exceptions either.
michael@0 219
michael@0 220 {
michael@0 221 AutoSaveContextOptions asco(cx);
michael@0 222 ContextOptionsRef(cx).setDontReportUncaught(true);
michael@0 223 RootedValue arg(cx, JS::ObjectValue(*id));
michael@0 224 success = JS_CallFunctionValue(cx, jsobj, fun, arg, &retval);
michael@0 225 }
michael@0 226
michael@0 227 if (!success && JS_IsExceptionPending(cx)) {
michael@0 228 RootedValue jsexception(cx, NullValue());
michael@0 229
michael@0 230 if (JS_GetPendingException(cx, &jsexception)) {
michael@0 231 nsresult rv;
michael@0 232 if (jsexception.isObject()) {
michael@0 233 // XPConnect may have constructed an object to represent a
michael@0 234 // C++ QI failure. See if that is the case.
michael@0 235 using namespace mozilla::dom;
michael@0 236 Exception *e = nullptr;
michael@0 237 UNWRAP_OBJECT(Exception, &jsexception.toObject(), e);
michael@0 238
michael@0 239 if (e &&
michael@0 240 NS_SUCCEEDED(e->GetResult(&rv)) &&
michael@0 241 rv == NS_NOINTERFACE) {
michael@0 242 JS_ClearPendingException(cx);
michael@0 243 }
michael@0 244 } else if (JSVAL_IS_NUMBER(jsexception)) {
michael@0 245 // JS often throws an nsresult.
michael@0 246 if (JSVAL_IS_DOUBLE(jsexception))
michael@0 247 // Visual Studio 9 doesn't allow casting directly from
michael@0 248 // a double to an enumeration type, contrary to
michael@0 249 // 5.2.9(10) of C++11, so add an intermediate cast.
michael@0 250 rv = (nsresult)(uint32_t)(JSVAL_TO_DOUBLE(jsexception));
michael@0 251 else
michael@0 252 rv = (nsresult)(JSVAL_TO_INT(jsexception));
michael@0 253
michael@0 254 if (rv == NS_NOINTERFACE)
michael@0 255 JS_ClearPendingException(cx);
michael@0 256 }
michael@0 257 }
michael@0 258
michael@0 259 // Don't report if reporting was disabled by someone else.
michael@0 260 if (!ContextOptionsRef(cx).dontReportUncaught())
michael@0 261 JS_ReportPendingException(cx);
michael@0 262 } else if (!success) {
michael@0 263 NS_WARNING("QI hook ran OOMed - this is probably a bug!");
michael@0 264 }
michael@0 265 }
michael@0 266
michael@0 267 if (success)
michael@0 268 success = JS_ValueToObject(cx, retval, &retObj);
michael@0 269
michael@0 270 return success ? retObj.get() : nullptr;
michael@0 271 }
michael@0 272
michael@0 273 /***************************************************************************/
michael@0 274
michael@0 275 static bool
michael@0 276 GetNamedPropertyAsVariantRaw(XPCCallContext& ccx,
michael@0 277 HandleObject aJSObj,
michael@0 278 HandleId aName,
michael@0 279 nsIVariant** aResult,
michael@0 280 nsresult* pErr)
michael@0 281 {
michael@0 282 nsXPTType type = nsXPTType((uint8_t)TD_INTERFACE_TYPE);
michael@0 283 RootedValue val(ccx);
michael@0 284
michael@0 285 return JS_GetPropertyById(ccx, aJSObj, aName, &val) &&
michael@0 286 // Note that this always takes the T_INTERFACE path through
michael@0 287 // JSData2Native, so the value passed for useAllocator
michael@0 288 // doesn't really matter. We pass true for consistency.
michael@0 289 XPCConvert::JSData2Native(aResult, val, type, true,
michael@0 290 &NS_GET_IID(nsIVariant), pErr);
michael@0 291 }
michael@0 292
michael@0 293 // static
michael@0 294 nsresult
michael@0 295 nsXPCWrappedJSClass::GetNamedPropertyAsVariant(XPCCallContext& ccx,
michael@0 296 JSObject* aJSObjArg,
michael@0 297 const nsAString& aName,
michael@0 298 nsIVariant** aResult)
michael@0 299 {
michael@0 300 JSContext* cx = ccx.GetJSContext();
michael@0 301 RootedObject aJSObj(cx, aJSObjArg);
michael@0 302
michael@0 303 AutoScriptEvaluate scriptEval(cx);
michael@0 304 if (!scriptEval.StartEvaluating(aJSObj))
michael@0 305 return NS_ERROR_FAILURE;
michael@0 306
michael@0 307 // Wrap the string in a jsval after the AutoScriptEvaluate, so that the
michael@0 308 // resulting value ends up in the correct compartment.
michael@0 309 nsStringBuffer* buf;
michael@0 310 RootedValue value(cx);
michael@0 311 if (!XPCStringConvert::ReadableToJSVal(ccx, aName, &buf, &value))
michael@0 312 return NS_ERROR_OUT_OF_MEMORY;
michael@0 313 if (buf)
michael@0 314 buf->AddRef();
michael@0 315
michael@0 316 RootedId id(cx);
michael@0 317 nsresult rv = NS_OK;
michael@0 318 if (!JS_ValueToId(cx, value, &id) ||
michael@0 319 !GetNamedPropertyAsVariantRaw(ccx, aJSObj, id, aResult, &rv)) {
michael@0 320 if (NS_FAILED(rv))
michael@0 321 return rv;
michael@0 322 return NS_ERROR_FAILURE;
michael@0 323 }
michael@0 324 return NS_OK;
michael@0 325 }
michael@0 326
michael@0 327 /***************************************************************************/
michael@0 328
michael@0 329 // static
michael@0 330 nsresult
michael@0 331 nsXPCWrappedJSClass::BuildPropertyEnumerator(XPCCallContext& ccx,
michael@0 332 JSObject* aJSObjArg,
michael@0 333 nsISimpleEnumerator** aEnumerate)
michael@0 334 {
michael@0 335 JSContext* cx = ccx.GetJSContext();
michael@0 336 RootedObject aJSObj(cx, aJSObjArg);
michael@0 337
michael@0 338 AutoScriptEvaluate scriptEval(cx);
michael@0 339 if (!scriptEval.StartEvaluating(aJSObj))
michael@0 340 return NS_ERROR_FAILURE;
michael@0 341
michael@0 342 AutoIdArray idArray(cx, JS_Enumerate(cx, aJSObj));
michael@0 343 if (!idArray)
michael@0 344 return NS_ERROR_FAILURE;
michael@0 345
michael@0 346 nsCOMArray<nsIProperty> propertyArray(idArray.length());
michael@0 347 RootedId idName(cx);
michael@0 348 for (size_t i = 0; i < idArray.length(); i++) {
michael@0 349 idName = idArray[i];
michael@0 350
michael@0 351 nsCOMPtr<nsIVariant> value;
michael@0 352 nsresult rv;
michael@0 353 if (!GetNamedPropertyAsVariantRaw(ccx, aJSObj, idName,
michael@0 354 getter_AddRefs(value), &rv)) {
michael@0 355 if (NS_FAILED(rv))
michael@0 356 return rv;
michael@0 357 return NS_ERROR_FAILURE;
michael@0 358 }
michael@0 359
michael@0 360 RootedValue jsvalName(cx);
michael@0 361 if (!JS_IdToValue(cx, idName, &jsvalName))
michael@0 362 return NS_ERROR_FAILURE;
michael@0 363
michael@0 364 JSString* name = ToString(cx, jsvalName);
michael@0 365 if (!name)
michael@0 366 return NS_ERROR_FAILURE;
michael@0 367
michael@0 368 size_t length;
michael@0 369 const jschar *chars = JS_GetStringCharsAndLength(cx, name, &length);
michael@0 370 if (!chars)
michael@0 371 return NS_ERROR_FAILURE;
michael@0 372
michael@0 373 nsCOMPtr<nsIProperty> property =
michael@0 374 new xpcProperty(chars, (uint32_t) length, value);
michael@0 375
michael@0 376 if (!propertyArray.AppendObject(property))
michael@0 377 return NS_ERROR_FAILURE;
michael@0 378 }
michael@0 379
michael@0 380 return NS_NewArrayEnumerator(aEnumerate, propertyArray);
michael@0 381 }
michael@0 382
michael@0 383 /***************************************************************************/
michael@0 384
michael@0 385 NS_IMPL_ISUPPORTS(xpcProperty, nsIProperty)
michael@0 386
michael@0 387 xpcProperty::xpcProperty(const char16_t* aName, uint32_t aNameLen,
michael@0 388 nsIVariant* aValue)
michael@0 389 : mName(aName, aNameLen), mValue(aValue)
michael@0 390 {
michael@0 391 }
michael@0 392
michael@0 393 /* readonly attribute AString name; */
michael@0 394 NS_IMETHODIMP xpcProperty::GetName(nsAString & aName)
michael@0 395 {
michael@0 396 aName.Assign(mName);
michael@0 397 return NS_OK;
michael@0 398 }
michael@0 399
michael@0 400 /* readonly attribute nsIVariant value; */
michael@0 401 NS_IMETHODIMP xpcProperty::GetValue(nsIVariant * *aValue)
michael@0 402 {
michael@0 403 nsCOMPtr<nsIVariant> rval = mValue;
michael@0 404 rval.forget(aValue);
michael@0 405 return NS_OK;
michael@0 406 }
michael@0 407
michael@0 408 /***************************************************************************/
michael@0 409 // This 'WrappedJSIdentity' class and singleton allow us to figure out if
michael@0 410 // any given nsISupports* is implemented by a WrappedJS object. This is done
michael@0 411 // using a QueryInterface call on the interface pointer with our ID. If
michael@0 412 // that call returns NS_OK and the pointer is to our singleton, then the
michael@0 413 // interface must be implemented by a WrappedJS object. NOTE: the
michael@0 414 // 'WrappedJSIdentity' object is not a real XPCOM object and should not be
michael@0 415 // used for anything else (hence it is declared in this implementation file).
michael@0 416
michael@0 417 // {5C5C3BB0-A9BA-11d2-BA64-00805F8A5DD7}
michael@0 418 #define NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID \
michael@0 419 { 0x5c5c3bb0, 0xa9ba, 0x11d2, \
michael@0 420 { 0xba, 0x64, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
michael@0 421
michael@0 422 class WrappedJSIdentity
michael@0 423 {
michael@0 424 // no instance methods...
michael@0 425 public:
michael@0 426 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
michael@0 427
michael@0 428 static void* GetSingleton()
michael@0 429 {
michael@0 430 static WrappedJSIdentity* singleton = nullptr;
michael@0 431 if (!singleton)
michael@0 432 singleton = new WrappedJSIdentity();
michael@0 433 return (void*) singleton;
michael@0 434 }
michael@0 435 };
michael@0 436
michael@0 437 NS_DEFINE_STATIC_IID_ACCESSOR(WrappedJSIdentity,
michael@0 438 NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
michael@0 439
michael@0 440 /***************************************************************************/
michael@0 441
michael@0 442 // static
michael@0 443 bool
michael@0 444 nsXPCWrappedJSClass::IsWrappedJS(nsISupports* aPtr)
michael@0 445 {
michael@0 446 void* result;
michael@0 447 NS_PRECONDITION(aPtr, "null pointer");
michael@0 448 return aPtr &&
michael@0 449 NS_OK == aPtr->QueryInterface(NS_GET_IID(WrappedJSIdentity), &result) &&
michael@0 450 result == WrappedJSIdentity::GetSingleton();
michael@0 451 }
michael@0 452
michael@0 453 // NB: This will return the top JSContext on the JSContext stack if there is one,
michael@0 454 // before attempting to get the context from the wrapped JS object.
michael@0 455 static JSContext *
michael@0 456 GetContextFromObjectOrDefault(nsXPCWrappedJS* wrapper)
michael@0 457 {
michael@0 458 // First, try the cx stack.
michael@0 459 XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
michael@0 460 if (stack->Peek())
michael@0 461 return stack->Peek();
michael@0 462
michael@0 463 // If the cx stack is empty, try the wrapper's JSObject.
michael@0 464 JSCompartment *c = js::GetObjectCompartment(wrapper->GetJSObject());
michael@0 465 XPCContext *xpcc = EnsureCompartmentPrivate(c)->scope->GetContext();
michael@0 466 if (xpcc) {
michael@0 467 JSContext *cx = xpcc->GetJSContext();
michael@0 468 JS_AbortIfWrongThread(JS_GetRuntime(cx));
michael@0 469 return cx;
michael@0 470 }
michael@0 471
michael@0 472 // Fall back to the safe JSContext.
michael@0 473 return stack->GetSafeJSContext();
michael@0 474 }
michael@0 475
michael@0 476 NS_IMETHODIMP
michael@0 477 nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
michael@0 478 REFNSIID aIID,
michael@0 479 void** aInstancePtr)
michael@0 480 {
michael@0 481 if (aIID.Equals(NS_GET_IID(nsIXPConnectJSObjectHolder))) {
michael@0 482 NS_ADDREF(self);
michael@0 483 *aInstancePtr = (void*) static_cast<nsIXPConnectJSObjectHolder*>(self);
michael@0 484 return NS_OK;
michael@0 485 }
michael@0 486
michael@0 487 // Objects internal to xpconnect are the only objects that even know *how*
michael@0 488 // to ask for this iid. And none of them bother refcounting the thing.
michael@0 489 if (aIID.Equals(NS_GET_IID(WrappedJSIdentity))) {
michael@0 490 // asking to find out if this is a wrapper object
michael@0 491 *aInstancePtr = WrappedJSIdentity::GetSingleton();
michael@0 492 return NS_OK;
michael@0 493 }
michael@0 494
michael@0 495 if (aIID.Equals(NS_GET_IID(nsIPropertyBag))) {
michael@0 496 // We only want to expose one implementation from our aggregate.
michael@0 497 nsXPCWrappedJS* root = self->GetRootWrapper();
michael@0 498
michael@0 499 if (!root->IsValid()) {
michael@0 500 *aInstancePtr = nullptr;
michael@0 501 return NS_NOINTERFACE;
michael@0 502 }
michael@0 503
michael@0 504 NS_ADDREF(root);
michael@0 505 *aInstancePtr = (void*) static_cast<nsIPropertyBag*>(root);
michael@0 506 return NS_OK;
michael@0 507 }
michael@0 508
michael@0 509 // We can't have a cached wrapper.
michael@0 510 if (aIID.Equals(NS_GET_IID(nsWrapperCache))) {
michael@0 511 *aInstancePtr = nullptr;
michael@0 512 return NS_NOINTERFACE;
michael@0 513 }
michael@0 514
michael@0 515 AutoPushJSContext context(GetContextFromObjectOrDefault(self));
michael@0 516 XPCCallContext ccx(NATIVE_CALLER, context);
michael@0 517 if (!ccx.IsValid()) {
michael@0 518 *aInstancePtr = nullptr;
michael@0 519 return NS_NOINTERFACE;
michael@0 520 }
michael@0 521
michael@0 522 // We support nsISupportsWeakReference iff the root wrapped JSObject
michael@0 523 // claims to support it in its QueryInterface implementation.
michael@0 524 if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) {
michael@0 525 // We only want to expose one implementation from our aggregate.
michael@0 526 nsXPCWrappedJS* root = self->GetRootWrapper();
michael@0 527
michael@0 528 // Fail if JSObject doesn't claim support for nsISupportsWeakReference
michael@0 529 if (!root->IsValid() ||
michael@0 530 !CallQueryInterfaceOnJSObject(ccx, root->GetJSObject(), aIID)) {
michael@0 531 *aInstancePtr = nullptr;
michael@0 532 return NS_NOINTERFACE;
michael@0 533 }
michael@0 534
michael@0 535 NS_ADDREF(root);
michael@0 536 *aInstancePtr = (void*) static_cast<nsISupportsWeakReference*>(root);
michael@0 537 return NS_OK;
michael@0 538 }
michael@0 539
michael@0 540 // Checks for any existing wrapper explicitly constructed for this iid.
michael@0 541 // This includes the current 'self' wrapper. This also deals with the
michael@0 542 // nsISupports case (for which it returns mRoot).
michael@0 543 // Also check if asking for an interface from which one of our wrappers inherits.
michael@0 544 if (nsXPCWrappedJS* sibling = self->FindOrFindInherited(aIID)) {
michael@0 545 NS_ADDREF(sibling);
michael@0 546 *aInstancePtr = sibling->GetXPTCStub();
michael@0 547 return NS_OK;
michael@0 548 }
michael@0 549
michael@0 550 // else we do the more expensive stuff...
michael@0 551
michael@0 552 // check if the JSObject claims to implement this interface
michael@0 553 RootedObject jsobj(ccx, CallQueryInterfaceOnJSObject(ccx, self->GetJSObject(),
michael@0 554 aIID));
michael@0 555 if (jsobj) {
michael@0 556 // We can't use XPConvert::JSObject2NativeInterface() here
michael@0 557 // since that can find a XPCWrappedNative directly on the
michael@0 558 // proto chain, and we don't want that here. We need to find
michael@0 559 // the actual JS object that claimed it supports the interface
michael@0 560 // we're looking for or we'll potentially bypass security
michael@0 561 // checks etc by calling directly through to a native found on
michael@0 562 // the prototype chain.
michael@0 563 //
michael@0 564 // Instead, simply do the nsXPCWrappedJS part of
michael@0 565 // XPConvert::JSObject2NativeInterface() here to make sure we
michael@0 566 // get a new (or used) nsXPCWrappedJS.
michael@0 567 nsXPCWrappedJS* wrapper;
michael@0 568 nsresult rv = nsXPCWrappedJS::GetNewOrUsed(jsobj, aIID, &wrapper);
michael@0 569 if (NS_SUCCEEDED(rv) && wrapper) {
michael@0 570 // We need to go through the QueryInterface logic to make
michael@0 571 // this return the right thing for the various 'special'
michael@0 572 // interfaces; e.g. nsIPropertyBag.
michael@0 573 rv = wrapper->QueryInterface(aIID, aInstancePtr);
michael@0 574 NS_RELEASE(wrapper);
michael@0 575 return rv;
michael@0 576 }
michael@0 577 }
michael@0 578
michael@0 579 // else...
michael@0 580 // no can do
michael@0 581 *aInstancePtr = nullptr;
michael@0 582 return NS_NOINTERFACE;
michael@0 583 }
michael@0 584
michael@0 585 JSObject*
michael@0 586 nsXPCWrappedJSClass::GetRootJSObject(JSContext* cx, JSObject* aJSObjArg)
michael@0 587 {
michael@0 588 RootedObject aJSObj(cx, aJSObjArg);
michael@0 589 JSObject* result = CallQueryInterfaceOnJSObject(cx, aJSObj,
michael@0 590 NS_GET_IID(nsISupports));
michael@0 591 if (!result)
michael@0 592 return aJSObj;
michael@0 593 JSObject* inner = js::UncheckedUnwrap(result);
michael@0 594 if (inner)
michael@0 595 return inner;
michael@0 596 return result;
michael@0 597 }
michael@0 598
michael@0 599 void
michael@0 600 xpcWrappedJSErrorReporter(JSContext *cx, const char *message,
michael@0 601 JSErrorReport *report)
michael@0 602 {
michael@0 603 if (report) {
michael@0 604 // If it is an exception report, then we can just deal with the
michael@0 605 // exception later (if not caught in the JS code).
michael@0 606 if (JSREPORT_IS_EXCEPTION(report->flags)) {
michael@0 607 // XXX We have a problem with error reports from uncaught exceptions.
michael@0 608 //
michael@0 609 // http://bugzilla.mozilla.org/show_bug.cgi?id=66453
michael@0 610 //
michael@0 611 // The issue is...
michael@0 612 //
michael@0 613 // We can't assume that the exception will *stay* uncaught. So, if
michael@0 614 // we build an nsIXPCException here and the underlying exception
michael@0 615 // really is caught before our script is done running then we blow
michael@0 616 // it by returning failure to our caller when the script didn't
michael@0 617 // really fail. However, This report contains error location info
michael@0 618 // that is no longer available after the script is done. So, if the
michael@0 619 // exception really is not caught (and is a non-engine exception)
michael@0 620 // then we've lost the oportunity to capture the script location
michael@0 621 // info that we *could* have captured here.
michael@0 622 //
michael@0 623 // This is expecially an issue with nested evaluations.
michael@0 624 //
michael@0 625 // Perhaps we could capture an expception here and store it as
michael@0 626 // 'provisional' and then later if there is a pending exception
michael@0 627 // when the script is done then we could maybe compare that in some
michael@0 628 // way with the 'provisional' one in which we captured location info.
michael@0 629 // We would not want to assume that the one discovered here is the
michael@0 630 // same one that is later detected. This could cause us to lie.
michael@0 631 //
michael@0 632 // The thing is. we do not currently store the right stuff to compare
michael@0 633 // these two nsIXPCExceptions (triggered by the same exception jsval
michael@0 634 // in the engine). Maybe we should store the jsval and compare that?
michael@0 635 // Maybe without even rooting it since we will not dereference it.
michael@0 636 // This is inexact, but maybe the right thing to do?
michael@0 637 //
michael@0 638 // if (report->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)) ...
michael@0 639 //
michael@0 640
michael@0 641 return;
michael@0 642 }
michael@0 643
michael@0 644 if (JSREPORT_IS_WARNING(report->flags)) {
michael@0 645 // XXX printf the warning (#ifdef DEBUG only!).
michael@0 646 // XXX send the warning to the console service.
michael@0 647 return;
michael@0 648 }
michael@0 649 }
michael@0 650
michael@0 651 XPCCallContext ccx(NATIVE_CALLER, cx);
michael@0 652 if (!ccx.IsValid())
michael@0 653 return;
michael@0 654
michael@0 655 nsCOMPtr<nsIException> e;
michael@0 656 XPCConvert::JSErrorToXPCException(message, nullptr, nullptr, report,
michael@0 657 getter_AddRefs(e));
michael@0 658 if (e)
michael@0 659 ccx.GetXPCContext()->SetException(e);
michael@0 660 }
michael@0 661
michael@0 662 bool
michael@0 663 nsXPCWrappedJSClass::GetArraySizeFromParam(JSContext* cx,
michael@0 664 const XPTMethodDescriptor* method,
michael@0 665 const nsXPTParamInfo& param,
michael@0 666 uint16_t methodIndex,
michael@0 667 uint8_t paramIndex,
michael@0 668 nsXPTCMiniVariant* nativeParams,
michael@0 669 uint32_t* result)
michael@0 670 {
michael@0 671 uint8_t argnum;
michael@0 672 nsresult rv;
michael@0 673
michael@0 674 rv = mInfo->GetSizeIsArgNumberForParam(methodIndex, &param, 0, &argnum);
michael@0 675 if (NS_FAILED(rv))
michael@0 676 return false;
michael@0 677
michael@0 678 const nsXPTParamInfo& arg_param = method->params[argnum];
michael@0 679
michael@0 680 // This should be enforced by the xpidl compiler, but it's not.
michael@0 681 // See bug 695235.
michael@0 682 MOZ_ASSERT(arg_param.GetType().TagPart() == nsXPTType::T_U32,
michael@0 683 "size_is references parameter of invalid type.");
michael@0 684
michael@0 685 if (arg_param.IsIndirect())
michael@0 686 *result = *(uint32_t*)nativeParams[argnum].val.p;
michael@0 687 else
michael@0 688 *result = nativeParams[argnum].val.u32;
michael@0 689
michael@0 690 return true;
michael@0 691 }
michael@0 692
michael@0 693 bool
michael@0 694 nsXPCWrappedJSClass::GetInterfaceTypeFromParam(JSContext* cx,
michael@0 695 const XPTMethodDescriptor* method,
michael@0 696 const nsXPTParamInfo& param,
michael@0 697 uint16_t methodIndex,
michael@0 698 const nsXPTType& type,
michael@0 699 nsXPTCMiniVariant* nativeParams,
michael@0 700 nsID* result)
michael@0 701 {
michael@0 702 uint8_t type_tag = type.TagPart();
michael@0 703
michael@0 704 if (type_tag == nsXPTType::T_INTERFACE) {
michael@0 705 if (NS_SUCCEEDED(GetInterfaceInfo()->
michael@0 706 GetIIDForParamNoAlloc(methodIndex, &param, result))) {
michael@0 707 return true;
michael@0 708 }
michael@0 709 } else if (type_tag == nsXPTType::T_INTERFACE_IS) {
michael@0 710 uint8_t argnum;
michael@0 711 nsresult rv;
michael@0 712 rv = mInfo->GetInterfaceIsArgNumberForParam(methodIndex,
michael@0 713 &param, &argnum);
michael@0 714 if (NS_FAILED(rv))
michael@0 715 return false;
michael@0 716
michael@0 717 const nsXPTParamInfo& arg_param = method->params[argnum];
michael@0 718 const nsXPTType& arg_type = arg_param.GetType();
michael@0 719
michael@0 720 if (arg_type.TagPart() == nsXPTType::T_IID) {
michael@0 721 if (arg_param.IsIndirect()) {
michael@0 722 nsID** p = (nsID**) nativeParams[argnum].val.p;
michael@0 723 if (!p || !*p)
michael@0 724 return false;
michael@0 725 *result = **p;
michael@0 726 } else {
michael@0 727 nsID* p = (nsID*) nativeParams[argnum].val.p;
michael@0 728 if (!p)
michael@0 729 return false;
michael@0 730 *result = *p;
michael@0 731 }
michael@0 732 return true;
michael@0 733 }
michael@0 734 }
michael@0 735 return false;
michael@0 736 }
michael@0 737
michael@0 738 void
michael@0 739 nsXPCWrappedJSClass::CleanupPointerArray(const nsXPTType& datum_type,
michael@0 740 uint32_t array_count,
michael@0 741 void** arrayp)
michael@0 742 {
michael@0 743 if (datum_type.IsInterfacePointer()) {
michael@0 744 nsISupports** pp = (nsISupports**) arrayp;
michael@0 745 for (uint32_t k = 0; k < array_count; k++) {
michael@0 746 nsISupports* p = pp[k];
michael@0 747 NS_IF_RELEASE(p);
michael@0 748 }
michael@0 749 } else {
michael@0 750 void** pp = (void**) arrayp;
michael@0 751 for (uint32_t k = 0; k < array_count; k++) {
michael@0 752 void* p = pp[k];
michael@0 753 if (p) nsMemory::Free(p);
michael@0 754 }
michael@0 755 }
michael@0 756 }
michael@0 757
michael@0 758 void
michael@0 759 nsXPCWrappedJSClass::CleanupPointerTypeObject(const nsXPTType& type,
michael@0 760 void** pp)
michael@0 761 {
michael@0 762 MOZ_ASSERT(pp,"null pointer");
michael@0 763 if (type.IsInterfacePointer()) {
michael@0 764 nsISupports* p = *((nsISupports**)pp);
michael@0 765 if (p) p->Release();
michael@0 766 } else {
michael@0 767 void* p = *((void**)pp);
michael@0 768 if (p) nsMemory::Free(p);
michael@0 769 }
michael@0 770 }
michael@0 771
michael@0 772 class AutoClearPendingException
michael@0 773 {
michael@0 774 public:
michael@0 775 AutoClearPendingException(JSContext *cx) : mCx(cx) { }
michael@0 776 ~AutoClearPendingException() { JS_ClearPendingException(mCx); }
michael@0 777 private:
michael@0 778 JSContext* mCx;
michael@0 779 };
michael@0 780
michael@0 781 nsresult
michael@0 782 nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
michael@0 783 const char * aPropertyName,
michael@0 784 const char * anInterfaceName,
michael@0 785 bool aForceReport)
michael@0 786 {
michael@0 787 XPCContext * xpcc = ccx.GetXPCContext();
michael@0 788 JSContext * cx = ccx.GetJSContext();
michael@0 789 nsCOMPtr<nsIException> xpc_exception;
michael@0 790 /* this one would be set by our error reporter */
michael@0 791
michael@0 792 xpcc->GetException(getter_AddRefs(xpc_exception));
michael@0 793 if (xpc_exception)
michael@0 794 xpcc->SetException(nullptr);
michael@0 795
michael@0 796 // get this right away in case we do something below to cause JS code
michael@0 797 // to run on this JSContext
michael@0 798 nsresult pending_result = xpcc->GetPendingResult();
michael@0 799
michael@0 800 RootedValue js_exception(cx);
michael@0 801 bool is_js_exception = JS_GetPendingException(cx, &js_exception);
michael@0 802
michael@0 803 /* JS might throw an expection whether the reporter was called or not */
michael@0 804 if (is_js_exception) {
michael@0 805 if (!xpc_exception)
michael@0 806 XPCConvert::JSValToXPCException(&js_exception, anInterfaceName,
michael@0 807 aPropertyName,
michael@0 808 getter_AddRefs(xpc_exception));
michael@0 809
michael@0 810 /* cleanup and set failed even if we can't build an exception */
michael@0 811 if (!xpc_exception) {
michael@0 812 XPCJSRuntime::Get()->SetPendingException(nullptr); // XXX necessary?
michael@0 813 }
michael@0 814 }
michael@0 815
michael@0 816 AutoClearPendingException acpe(cx);
michael@0 817
michael@0 818 if (xpc_exception) {
michael@0 819 nsresult e_result;
michael@0 820 if (NS_SUCCEEDED(xpc_exception->GetResult(&e_result))) {
michael@0 821 // Figure out whether or not we should report this exception.
michael@0 822 bool reportable = xpc_IsReportableErrorCode(e_result);
michael@0 823 if (reportable) {
michael@0 824 // Always want to report forced exceptions and XPConnect's own
michael@0 825 // errors.
michael@0 826 reportable = aForceReport ||
michael@0 827 NS_ERROR_GET_MODULE(e_result) == NS_ERROR_MODULE_XPCONNECT;
michael@0 828
michael@0 829 // See if an environment variable was set or someone has told us
michael@0 830 // that a user pref was set indicating that we should report all
michael@0 831 // exceptions.
michael@0 832 if (!reportable)
michael@0 833 reportable = nsXPConnect::ReportAllJSExceptions();
michael@0 834
michael@0 835 // Finally, check to see if this is the last JS frame on the
michael@0 836 // stack. If so then we always want to report it.
michael@0 837 if (!reportable)
michael@0 838 reportable = !JS::DescribeScriptedCaller(cx);
michael@0 839
michael@0 840 // Ugly special case for GetInterface. It's "special" in the
michael@0 841 // same way as QueryInterface in that a failure is not
michael@0 842 // exceptional and shouldn't be reported. We have to do this
michael@0 843 // check here instead of in xpcwrappedjs (like we do for QI) to
michael@0 844 // avoid adding extra code to all xpcwrappedjs objects.
michael@0 845 if (reportable && e_result == NS_ERROR_NO_INTERFACE &&
michael@0 846 !strcmp(anInterfaceName, "nsIInterfaceRequestor") &&
michael@0 847 !strcmp(aPropertyName, "getInterface")) {
michael@0 848 reportable = false;
michael@0 849 }
michael@0 850
michael@0 851 // More special case, see bug 877760.
michael@0 852 if (e_result == NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) {
michael@0 853 reportable = false;
michael@0 854 }
michael@0 855 }
michael@0 856
michael@0 857 // Try to use the error reporter set on the context to handle this
michael@0 858 // error if it came from a JS exception.
michael@0 859 if (reportable && is_js_exception &&
michael@0 860 JS_GetErrorReporter(cx) != xpcWrappedJSErrorReporter)
michael@0 861 {
michael@0 862 // If the error reporter ignores the error, it will call
michael@0 863 // xpc->MarkErrorUnreported().
michael@0 864 xpcc->ClearUnreportedError();
michael@0 865 reportable = !JS_ReportPendingException(cx);
michael@0 866 if (!xpcc->WasErrorReported())
michael@0 867 reportable = true;
michael@0 868 }
michael@0 869
michael@0 870 if (reportable) {
michael@0 871 if (nsContentUtils::DOMWindowDumpEnabled()) {
michael@0 872 static const char line[] =
michael@0 873 "************************************************************\n";
michael@0 874 static const char preamble[] =
michael@0 875 "* Call to xpconnect wrapped JSObject produced this error: *\n";
michael@0 876 static const char cant_get_text[] =
michael@0 877 "FAILED TO GET TEXT FROM EXCEPTION\n";
michael@0 878
michael@0 879 fputs(line, stdout);
michael@0 880 fputs(preamble, stdout);
michael@0 881 nsCString text;
michael@0 882 if (NS_SUCCEEDED(xpc_exception->ToString(text)) &&
michael@0 883 !text.IsEmpty()) {
michael@0 884 fputs(text.get(), stdout);
michael@0 885 fputs("\n", stdout);
michael@0 886 } else
michael@0 887 fputs(cant_get_text, stdout);
michael@0 888 fputs(line, stdout);
michael@0 889 }
michael@0 890
michael@0 891 // Log the exception to the JS Console, so that users can do
michael@0 892 // something with it.
michael@0 893 nsCOMPtr<nsIConsoleService> consoleService
michael@0 894 (do_GetService(XPC_CONSOLE_CONTRACTID));
michael@0 895 if (nullptr != consoleService) {
michael@0 896 nsresult rv;
michael@0 897 nsCOMPtr<nsIScriptError> scriptError;
michael@0 898 nsCOMPtr<nsISupports> errorData;
michael@0 899 rv = xpc_exception->GetData(getter_AddRefs(errorData));
michael@0 900 if (NS_SUCCEEDED(rv))
michael@0 901 scriptError = do_QueryInterface(errorData);
michael@0 902
michael@0 903 if (nullptr == scriptError) {
michael@0 904 // No luck getting one from the exception, so
michael@0 905 // try to cook one up.
michael@0 906 scriptError = do_CreateInstance(XPC_SCRIPT_ERROR_CONTRACTID);
michael@0 907 if (nullptr != scriptError) {
michael@0 908 nsCString newMessage;
michael@0 909 rv = xpc_exception->ToString(newMessage);
michael@0 910 if (NS_SUCCEEDED(rv)) {
michael@0 911 // try to get filename, lineno from the first
michael@0 912 // stack frame location.
michael@0 913 int32_t lineNumber = 0;
michael@0 914 nsString sourceName;
michael@0 915
michael@0 916 nsCOMPtr<nsIStackFrame> location;
michael@0 917 xpc_exception->
michael@0 918 GetLocation(getter_AddRefs(location));
michael@0 919 if (location) {
michael@0 920 // Get line number w/o checking; 0 is ok.
michael@0 921 location->GetLineNumber(&lineNumber);
michael@0 922
michael@0 923 // get a filename.
michael@0 924 rv = location->GetFilename(sourceName);
michael@0 925 }
michael@0 926
michael@0 927 rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(newMessage),
michael@0 928 sourceName,
michael@0 929 EmptyString(),
michael@0 930 lineNumber, 0, 0,
michael@0 931 "XPConnect JavaScript",
michael@0 932 nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
michael@0 933 if (NS_FAILED(rv))
michael@0 934 scriptError = nullptr;
michael@0 935 }
michael@0 936 }
michael@0 937 }
michael@0 938 if (nullptr != scriptError)
michael@0 939 consoleService->LogMessage(scriptError);
michael@0 940 }
michael@0 941 }
michael@0 942 // Whether or not it passes the 'reportable' test, it might
michael@0 943 // still be an error and we have to do the right thing here...
michael@0 944 if (NS_FAILED(e_result)) {
michael@0 945 XPCJSRuntime::Get()->SetPendingException(xpc_exception);
michael@0 946 return e_result;
michael@0 947 }
michael@0 948 }
michael@0 949 } else {
michael@0 950 // see if JS code signaled failure result without throwing exception
michael@0 951 if (NS_FAILED(pending_result)) {
michael@0 952 return pending_result;
michael@0 953 }
michael@0 954 }
michael@0 955 return NS_ERROR_FAILURE;
michael@0 956 }
michael@0 957
michael@0 958 NS_IMETHODIMP
michael@0 959 nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
michael@0 960 const XPTMethodDescriptor* info_,
michael@0 961 nsXPTCMiniVariant* nativeParams)
michael@0 962 {
michael@0 963 jsval* sp = nullptr;
michael@0 964 jsval* argv = nullptr;
michael@0 965 uint8_t i;
michael@0 966 nsresult retval = NS_ERROR_FAILURE;
michael@0 967 nsresult pending_result = NS_OK;
michael@0 968 bool success;
michael@0 969 bool readyToDoTheCall = false;
michael@0 970 nsID param_iid;
michael@0 971 const nsXPTMethodInfo* info = static_cast<const nsXPTMethodInfo*>(info_);
michael@0 972 const char* name = info->name;
michael@0 973 bool foundDependentParam;
michael@0 974
michael@0 975 // Make sure not to set the callee on ccx until after we've gone through
michael@0 976 // the whole nsIXPCFunctionThisTranslator bit. That code uses ccx to
michael@0 977 // convert natives to JSObjects, but we do NOT plan to pass those JSObjects
michael@0 978 // to our real callee.
michael@0 979 AutoPushJSContext context(GetContextFromObjectOrDefault(wrapper));
michael@0 980 XPCCallContext ccx(NATIVE_CALLER, context);
michael@0 981 if (!ccx.IsValid())
michael@0 982 return retval;
michael@0 983
michael@0 984 XPCContext *xpcc = ccx.GetXPCContext();
michael@0 985 JSContext *cx = ccx.GetJSContext();
michael@0 986
michael@0 987 if (!cx || !xpcc || !IsReflectable(methodIndex))
michael@0 988 return NS_ERROR_FAILURE;
michael@0 989
michael@0 990 // [implicit_jscontext] and [optional_argc] have a different calling
michael@0 991 // convention, which we don't support for JS-implemented components.
michael@0 992 if (info->WantsOptArgc() || info->WantsContext()) {
michael@0 993 const char *str = "IDL methods marked with [implicit_jscontext] "
michael@0 994 "or [optional_argc] may not be implemented in JS";
michael@0 995 // Throw and warn for good measure.
michael@0 996 JS_ReportError(cx, str);
michael@0 997 NS_WARNING(str);
michael@0 998 return NS_ERROR_FAILURE;
michael@0 999 }
michael@0 1000
michael@0 1001 RootedValue fval(cx);
michael@0 1002 RootedObject obj(cx, wrapper->GetJSObject());
michael@0 1003 RootedObject thisObj(cx, obj);
michael@0 1004
michael@0 1005 JSAutoCompartment ac(cx, obj);
michael@0 1006
michael@0 1007 AutoValueVector args(cx);
michael@0 1008 AutoScriptEvaluate scriptEval(cx);
michael@0 1009
michael@0 1010 // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
michael@0 1011 uint8_t paramCount = info->num_args;
michael@0 1012 uint8_t argc = paramCount -
michael@0 1013 (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
michael@0 1014
michael@0 1015 if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter))
michael@0 1016 goto pre_call_clean_up;
michael@0 1017
michael@0 1018 xpcc->SetPendingResult(pending_result);
michael@0 1019 xpcc->SetException(nullptr);
michael@0 1020 XPCJSRuntime::Get()->SetPendingException(nullptr);
michael@0 1021
michael@0 1022 // We use js_Invoke so that the gcthings we use as args will be rooted by
michael@0 1023 // the engine as we do conversions and prepare to do the function call.
michael@0 1024
michael@0 1025 // setup stack
michael@0 1026
michael@0 1027 // if this isn't a function call then we don't need to push extra stuff
michael@0 1028 if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) {
michael@0 1029 // We get fval before allocating the stack to avoid gc badness that can
michael@0 1030 // happen if the GetProperty call leaves our request and the gc runs
michael@0 1031 // while the stack we allocate contains garbage.
michael@0 1032
michael@0 1033 // If the interface is marked as a [function] then we will assume that
michael@0 1034 // our JSObject is a function and not an object with a named method.
michael@0 1035
michael@0 1036 bool isFunction;
michael@0 1037 if (NS_FAILED(mInfo->IsFunction(&isFunction)))
michael@0 1038 goto pre_call_clean_up;
michael@0 1039
michael@0 1040 // In the xpidl [function] case we are making sure now that the
michael@0 1041 // JSObject is callable. If it is *not* callable then we silently
michael@0 1042 // fallback to looking up the named property...
michael@0 1043 // (because jst says he thinks this fallback is 'The Right Thing'.)
michael@0 1044 //
michael@0 1045 // In the normal (non-function) case we just lookup the property by
michael@0 1046 // name and as long as the object has such a named property we go ahead
michael@0 1047 // and try to make the call. If it turns out the named property is not
michael@0 1048 // a callable object then the JS engine will throw an error and we'll
michael@0 1049 // pass this along to the caller as an exception/result code.
michael@0 1050
michael@0 1051 fval = ObjectValue(*obj);
michael@0 1052 if (isFunction &&
michael@0 1053 JS_TypeOfValue(ccx, fval) == JSTYPE_FUNCTION) {
michael@0 1054
michael@0 1055 // We may need to translate the 'this' for the function object.
michael@0 1056
michael@0 1057 if (paramCount) {
michael@0 1058 const nsXPTParamInfo& firstParam = info->params[0];
michael@0 1059 if (firstParam.IsIn()) {
michael@0 1060 const nsXPTType& firstType = firstParam.GetType();
michael@0 1061
michael@0 1062 if (firstType.IsInterfacePointer()) {
michael@0 1063 nsIXPCFunctionThisTranslator* translator;
michael@0 1064
michael@0 1065 IID2ThisTranslatorMap* map =
michael@0 1066 mRuntime->GetThisTranslatorMap();
michael@0 1067
michael@0 1068 translator = map->Find(mIID);
michael@0 1069
michael@0 1070 if (translator) {
michael@0 1071 nsCOMPtr<nsISupports> newThis;
michael@0 1072 if (NS_FAILED(translator->
michael@0 1073 TranslateThis((nsISupports*)nativeParams[0].val.p,
michael@0 1074 getter_AddRefs(newThis)))) {
michael@0 1075 goto pre_call_clean_up;
michael@0 1076 }
michael@0 1077 if (newThis) {
michael@0 1078 RootedValue v(cx);
michael@0 1079 xpcObjectHelper helper(newThis);
michael@0 1080 bool ok =
michael@0 1081 XPCConvert::NativeInterface2JSObject(
michael@0 1082 &v, nullptr, helper, nullptr,
michael@0 1083 nullptr, false, nullptr);
michael@0 1084 if (!ok) {
michael@0 1085 goto pre_call_clean_up;
michael@0 1086 }
michael@0 1087 thisObj = JSVAL_TO_OBJECT(v);
michael@0 1088 if (!JS_WrapObject(cx, &thisObj))
michael@0 1089 goto pre_call_clean_up;
michael@0 1090 }
michael@0 1091 }
michael@0 1092 }
michael@0 1093 }
michael@0 1094 }
michael@0 1095 } else {
michael@0 1096 if (!JS_GetProperty(cx, obj, name, &fval))
michael@0 1097 goto pre_call_clean_up;
michael@0 1098 // XXX We really want to factor out the error reporting better and
michael@0 1099 // specifically report the failure to find a function with this name.
michael@0 1100 // This is what we do below if the property is found but is not a
michael@0 1101 // function. We just need to factor better so we can get to that
michael@0 1102 // reporting path from here.
michael@0 1103
michael@0 1104 thisObj = obj;
michael@0 1105 }
michael@0 1106 }
michael@0 1107
michael@0 1108 if (!args.resize(argc)) {
michael@0 1109 retval = NS_ERROR_OUT_OF_MEMORY;
michael@0 1110 goto pre_call_clean_up;
michael@0 1111 }
michael@0 1112
michael@0 1113 argv = args.begin();
michael@0 1114 sp = argv;
michael@0 1115
michael@0 1116 // build the args
michael@0 1117 // NB: This assignment *looks* wrong because we haven't yet called our
michael@0 1118 // function. However, we *have* already entered the compartmen that we're
michael@0 1119 // about to call, and that's the global that we want here. In other words:
michael@0 1120 // we're trusting the JS engine to come up with a good global to use for
michael@0 1121 // our object (whatever it was).
michael@0 1122 for (i = 0; i < argc; i++) {
michael@0 1123 const nsXPTParamInfo& param = info->params[i];
michael@0 1124 const nsXPTType& type = param.GetType();
michael@0 1125 nsXPTType datum_type;
michael@0 1126 uint32_t array_count;
michael@0 1127 bool isArray = type.IsArray();
michael@0 1128 RootedValue val(cx, NullValue());
michael@0 1129 bool isSizedString = isArray ?
michael@0 1130 false :
michael@0 1131 type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
michael@0 1132 type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
michael@0 1133
michael@0 1134
michael@0 1135 // verify that null was not passed for 'out' param
michael@0 1136 if (param.IsOut() && !nativeParams[i].val.p) {
michael@0 1137 retval = NS_ERROR_INVALID_ARG;
michael@0 1138 goto pre_call_clean_up;
michael@0 1139 }
michael@0 1140
michael@0 1141 if (isArray) {
michael@0 1142 if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
michael@0 1143 &datum_type)))
michael@0 1144 goto pre_call_clean_up;
michael@0 1145 } else
michael@0 1146 datum_type = type;
michael@0 1147
michael@0 1148 if (param.IsIn()) {
michael@0 1149 nsXPTCMiniVariant* pv;
michael@0 1150
michael@0 1151 if (param.IsIndirect())
michael@0 1152 pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
michael@0 1153 else
michael@0 1154 pv = &nativeParams[i];
michael@0 1155
michael@0 1156 if (datum_type.IsInterfacePointer() &&
michael@0 1157 !GetInterfaceTypeFromParam(cx, info, param, methodIndex,
michael@0 1158 datum_type, nativeParams,
michael@0 1159 &param_iid))
michael@0 1160 goto pre_call_clean_up;
michael@0 1161
michael@0 1162 if (isArray || isSizedString) {
michael@0 1163 if (!GetArraySizeFromParam(cx, info, param, methodIndex,
michael@0 1164 i, nativeParams, &array_count))
michael@0 1165 goto pre_call_clean_up;
michael@0 1166 }
michael@0 1167
michael@0 1168 if (isArray) {
michael@0 1169 if (!XPCConvert::NativeArray2JS(&val,
michael@0 1170 (const void**)&pv->val,
michael@0 1171 datum_type, &param_iid,
michael@0 1172 array_count, nullptr))
michael@0 1173 goto pre_call_clean_up;
michael@0 1174 } else if (isSizedString) {
michael@0 1175 if (!XPCConvert::NativeStringWithSize2JS(&val,
michael@0 1176 (const void*)&pv->val,
michael@0 1177 datum_type,
michael@0 1178 array_count, nullptr))
michael@0 1179 goto pre_call_clean_up;
michael@0 1180 } else {
michael@0 1181 if (!XPCConvert::NativeData2JS(&val, &pv->val, type,
michael@0 1182 &param_iid, nullptr))
michael@0 1183 goto pre_call_clean_up;
michael@0 1184 }
michael@0 1185 }
michael@0 1186
michael@0 1187 if (param.IsOut() || param.IsDipper()) {
michael@0 1188 // create an 'out' object
michael@0 1189 RootedObject out_obj(cx, NewOutObject(cx, obj));
michael@0 1190 if (!out_obj) {
michael@0 1191 retval = NS_ERROR_OUT_OF_MEMORY;
michael@0 1192 goto pre_call_clean_up;
michael@0 1193 }
michael@0 1194
michael@0 1195 if (param.IsIn()) {
michael@0 1196 if (!JS_SetPropertyById(cx, out_obj,
michael@0 1197 mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
michael@0 1198 val)) {
michael@0 1199 goto pre_call_clean_up;
michael@0 1200 }
michael@0 1201 }
michael@0 1202 *sp++ = OBJECT_TO_JSVAL(out_obj);
michael@0 1203 } else
michael@0 1204 *sp++ = val;
michael@0 1205 }
michael@0 1206
michael@0 1207 readyToDoTheCall = true;
michael@0 1208
michael@0 1209 pre_call_clean_up:
michael@0 1210 // clean up any 'out' params handed in
michael@0 1211 for (i = 0; i < paramCount; i++) {
michael@0 1212 const nsXPTParamInfo& param = info->params[i];
michael@0 1213 if (!param.IsOut())
michael@0 1214 continue;
michael@0 1215
michael@0 1216 const nsXPTType& type = param.GetType();
michael@0 1217 if (!type.deprecated_IsPointer())
michael@0 1218 continue;
michael@0 1219 void* p;
michael@0 1220 if (!(p = nativeParams[i].val.p))
michael@0 1221 continue;
michael@0 1222
michael@0 1223 if (param.IsIn()) {
michael@0 1224 if (type.IsArray()) {
michael@0 1225 void** pp;
michael@0 1226 if (nullptr != (pp = *((void***)p))) {
michael@0 1227
michael@0 1228 // we need to get the array length and iterate the items
michael@0 1229 uint32_t array_count;
michael@0 1230 nsXPTType datum_type;
michael@0 1231
michael@0 1232 if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
michael@0 1233 1, &datum_type)) &&
michael@0 1234 datum_type.deprecated_IsPointer() &&
michael@0 1235 GetArraySizeFromParam(cx, info, param, methodIndex,
michael@0 1236 i, nativeParams, &array_count) &&
michael@0 1237 array_count) {
michael@0 1238
michael@0 1239 CleanupPointerArray(datum_type, array_count, pp);
michael@0 1240 }
michael@0 1241
michael@0 1242 // always release the array if it is inout
michael@0 1243 nsMemory::Free(pp);
michael@0 1244 }
michael@0 1245 } else
michael@0 1246 CleanupPointerTypeObject(type, (void**)p);
michael@0 1247 }
michael@0 1248 *((void**)p) = nullptr;
michael@0 1249 }
michael@0 1250
michael@0 1251 // Make sure "this" doesn't get deleted during this call.
michael@0 1252 nsCOMPtr<nsIXPCWrappedJSClass> kungFuDeathGrip(this);
michael@0 1253
michael@0 1254 if (!readyToDoTheCall)
michael@0 1255 return retval;
michael@0 1256
michael@0 1257 // do the deed - note exceptions
michael@0 1258
michael@0 1259 JS_ClearPendingException(cx);
michael@0 1260
michael@0 1261 RootedValue rval(cx);
michael@0 1262 if (XPT_MD_IS_GETTER(info->flags)) {
michael@0 1263 success = JS_GetProperty(cx, obj, name, &rval);
michael@0 1264 } else if (XPT_MD_IS_SETTER(info->flags)) {
michael@0 1265 rval = *argv;
michael@0 1266 success = JS_SetProperty(cx, obj, name, rval);
michael@0 1267 } else {
michael@0 1268 if (!JSVAL_IS_PRIMITIVE(fval)) {
michael@0 1269 AutoSaveContextOptions asco(cx);
michael@0 1270 ContextOptionsRef(cx).setDontReportUncaught(true);
michael@0 1271
michael@0 1272 success = JS_CallFunctionValue(cx, thisObj, fval, args, &rval);
michael@0 1273 } else {
michael@0 1274 // The property was not an object so can't be a function.
michael@0 1275 // Let's build and 'throw' an exception.
michael@0 1276
michael@0 1277 static const nsresult code =
michael@0 1278 NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
michael@0 1279 static const char format[] = "%s \"%s\"";
michael@0 1280 const char * msg;
michael@0 1281 char* sz = nullptr;
michael@0 1282
michael@0 1283 if (nsXPCException::NameAndFormatForNSResult(code, nullptr, &msg) && msg)
michael@0 1284 sz = JS_smprintf(format, msg, name);
michael@0 1285
michael@0 1286 nsCOMPtr<nsIException> e;
michael@0 1287
michael@0 1288 XPCConvert::ConstructException(code, sz, GetInterfaceName(), name,
michael@0 1289 nullptr, getter_AddRefs(e), nullptr, nullptr);
michael@0 1290 xpcc->SetException(e);
michael@0 1291 if (sz)
michael@0 1292 JS_smprintf_free(sz);
michael@0 1293 success = false;
michael@0 1294 }
michael@0 1295 }
michael@0 1296
michael@0 1297 if (!success) {
michael@0 1298 bool forceReport;
michael@0 1299 if (NS_FAILED(mInfo->IsFunction(&forceReport)))
michael@0 1300 forceReport = false;
michael@0 1301
michael@0 1302 // May also want to check if we're moving from content->chrome and force
michael@0 1303 // a report in that case.
michael@0 1304
michael@0 1305 return CheckForException(ccx, name, GetInterfaceName(), forceReport);
michael@0 1306 }
michael@0 1307
michael@0 1308 XPCJSRuntime::Get()->SetPendingException(nullptr); // XXX necessary?
michael@0 1309
michael@0 1310 // convert out args and result
michael@0 1311 // NOTE: this is the total number of native params, not just the args
michael@0 1312 // Convert independent params only.
michael@0 1313 // When we later convert the dependent params (if any) we will know that
michael@0 1314 // the params upon which they depend will have already been converted -
michael@0 1315 // regardless of ordering.
michael@0 1316
michael@0 1317 foundDependentParam = false;
michael@0 1318 for (i = 0; i < paramCount; i++) {
michael@0 1319 const nsXPTParamInfo& param = info->params[i];
michael@0 1320 MOZ_ASSERT(!param.IsShared(), "[shared] implies [noscript]!");
michael@0 1321 if (!param.IsOut() && !param.IsDipper())
michael@0 1322 continue;
michael@0 1323
michael@0 1324 const nsXPTType& type = param.GetType();
michael@0 1325 if (type.IsDependent()) {
michael@0 1326 foundDependentParam = true;
michael@0 1327 continue;
michael@0 1328 }
michael@0 1329
michael@0 1330 RootedValue val(cx);
michael@0 1331 uint8_t type_tag = type.TagPart();
michael@0 1332 nsXPTCMiniVariant* pv;
michael@0 1333
michael@0 1334 if (param.IsDipper())
michael@0 1335 pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p;
michael@0 1336 else
michael@0 1337 pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
michael@0 1338
michael@0 1339 if (param.IsRetval())
michael@0 1340 val = rval;
michael@0 1341 else if (argv[i].isPrimitive())
michael@0 1342 break;
michael@0 1343 else {
michael@0 1344 RootedObject obj(cx, &argv[i].toObject());
michael@0 1345 if (!JS_GetPropertyById(cx, obj,
michael@0 1346 mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
michael@0 1347 &val))
michael@0 1348 break;
michael@0 1349 }
michael@0 1350
michael@0 1351 // setup allocator and/or iid
michael@0 1352
michael@0 1353 if (type_tag == nsXPTType::T_INTERFACE) {
michael@0 1354 if (NS_FAILED(GetInterfaceInfo()->
michael@0 1355 GetIIDForParamNoAlloc(methodIndex, &param,
michael@0 1356 &param_iid)))
michael@0 1357 break;
michael@0 1358 }
michael@0 1359
michael@0 1360 // see bug #961488
michael@0 1361 #if (defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(_AIX)) && \
michael@0 1362 ((defined(__sparc) && !defined(__sparcv9) && !defined(__sparcv9__)) || \
michael@0 1363 (defined(__powerpc__) && !defined (__powerpc64__)))
michael@0 1364 if (type_tag == nsXPTType::T_JSVAL) {
michael@0 1365 if (!XPCConvert::JSData2Native(*(void**)(&pv->val), val, type,
michael@0 1366 !param.IsDipper(), &param_iid, nullptr))
michael@0 1367 break;
michael@0 1368 } else
michael@0 1369 #endif
michael@0 1370 {
michael@0 1371 if (!XPCConvert::JSData2Native(&pv->val, val, type,
michael@0 1372 !param.IsDipper(), &param_iid, nullptr))
michael@0 1373 break;
michael@0 1374 }
michael@0 1375 }
michael@0 1376
michael@0 1377 // if any params were dependent, then we must iterate again to convert them.
michael@0 1378 if (foundDependentParam && i == paramCount) {
michael@0 1379 for (i = 0; i < paramCount; i++) {
michael@0 1380 const nsXPTParamInfo& param = info->params[i];
michael@0 1381 if (!param.IsOut())
michael@0 1382 continue;
michael@0 1383
michael@0 1384 const nsXPTType& type = param.GetType();
michael@0 1385 if (!type.IsDependent())
michael@0 1386 continue;
michael@0 1387
michael@0 1388 RootedValue val(cx);
michael@0 1389 nsXPTCMiniVariant* pv;
michael@0 1390 nsXPTType datum_type;
michael@0 1391 uint32_t array_count;
michael@0 1392 bool isArray = type.IsArray();
michael@0 1393 bool isSizedString = isArray ?
michael@0 1394 false :
michael@0 1395 type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
michael@0 1396 type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
michael@0 1397
michael@0 1398 pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
michael@0 1399
michael@0 1400 if (param.IsRetval())
michael@0 1401 val = rval;
michael@0 1402 else {
michael@0 1403 RootedObject obj(cx, &argv[i].toObject());
michael@0 1404 if (!JS_GetPropertyById(cx, obj,
michael@0 1405 mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
michael@0 1406 &val))
michael@0 1407 break;
michael@0 1408 }
michael@0 1409
michael@0 1410 // setup allocator and/or iid
michael@0 1411
michael@0 1412 if (isArray) {
michael@0 1413 if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
michael@0 1414 &datum_type)))
michael@0 1415 break;
michael@0 1416 } else
michael@0 1417 datum_type = type;
michael@0 1418
michael@0 1419 if (datum_type.IsInterfacePointer()) {
michael@0 1420 if (!GetInterfaceTypeFromParam(cx, info, param, methodIndex,
michael@0 1421 datum_type, nativeParams,
michael@0 1422 &param_iid))
michael@0 1423 break;
michael@0 1424 }
michael@0 1425
michael@0 1426 if (isArray || isSizedString) {
michael@0 1427 if (!GetArraySizeFromParam(cx, info, param, methodIndex,
michael@0 1428 i, nativeParams, &array_count))
michael@0 1429 break;
michael@0 1430 }
michael@0 1431
michael@0 1432 if (isArray) {
michael@0 1433 if (array_count &&
michael@0 1434 !XPCConvert::JSArray2Native((void**)&pv->val, val,
michael@0 1435 array_count, datum_type,
michael@0 1436 &param_iid, nullptr))
michael@0 1437 break;
michael@0 1438 } else if (isSizedString) {
michael@0 1439 if (!XPCConvert::JSStringWithSize2Native((void*)&pv->val, val,
michael@0 1440 array_count, datum_type,
michael@0 1441 nullptr))
michael@0 1442 break;
michael@0 1443 } else {
michael@0 1444 if (!XPCConvert::JSData2Native(&pv->val, val, type,
michael@0 1445 true, &param_iid,
michael@0 1446 nullptr))
michael@0 1447 break;
michael@0 1448 }
michael@0 1449 }
michael@0 1450 }
michael@0 1451
michael@0 1452 if (i != paramCount) {
michael@0 1453 // We didn't manage all the result conversions!
michael@0 1454 // We have to cleanup any junk that *did* get converted.
michael@0 1455
michael@0 1456 for (uint8_t k = 0; k < i; k++) {
michael@0 1457 const nsXPTParamInfo& param = info->params[k];
michael@0 1458 if (!param.IsOut())
michael@0 1459 continue;
michael@0 1460 const nsXPTType& type = param.GetType();
michael@0 1461 if (!type.deprecated_IsPointer())
michael@0 1462 continue;
michael@0 1463 void* p;
michael@0 1464 if (!(p = nativeParams[k].val.p))
michael@0 1465 continue;
michael@0 1466
michael@0 1467 if (type.IsArray()) {
michael@0 1468 void** pp;
michael@0 1469 if (nullptr != (pp = *((void***)p))) {
michael@0 1470 // we need to get the array length and iterate the items
michael@0 1471 uint32_t array_count;
michael@0 1472 nsXPTType datum_type;
michael@0 1473
michael@0 1474 if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, &param,
michael@0 1475 1, &datum_type)) &&
michael@0 1476 datum_type.deprecated_IsPointer() &&
michael@0 1477 GetArraySizeFromParam(cx, info, param, methodIndex,
michael@0 1478 k, nativeParams, &array_count) &&
michael@0 1479 array_count) {
michael@0 1480
michael@0 1481 CleanupPointerArray(datum_type, array_count, pp);
michael@0 1482 }
michael@0 1483 nsMemory::Free(pp);
michael@0 1484 }
michael@0 1485 } else
michael@0 1486 CleanupPointerTypeObject(type, (void**)p);
michael@0 1487 *((void**)p) = nullptr;
michael@0 1488 }
michael@0 1489 } else {
michael@0 1490 // set to whatever the JS code might have set as the result
michael@0 1491 retval = pending_result;
michael@0 1492 }
michael@0 1493
michael@0 1494 return retval;
michael@0 1495 }
michael@0 1496
michael@0 1497 const char*
michael@0 1498 nsXPCWrappedJSClass::GetInterfaceName()
michael@0 1499 {
michael@0 1500 if (!mName)
michael@0 1501 mInfo->GetName(&mName);
michael@0 1502 return mName;
michael@0 1503 }
michael@0 1504
michael@0 1505 static void
michael@0 1506 FinalizeStub(JSFreeOp *fop, JSObject *obj)
michael@0 1507 {
michael@0 1508 }
michael@0 1509
michael@0 1510 static const JSClass XPCOutParamClass = {
michael@0 1511 "XPCOutParam",
michael@0 1512 0,
michael@0 1513 JS_PropertyStub,
michael@0 1514 JS_DeletePropertyStub,
michael@0 1515 JS_PropertyStub,
michael@0 1516 JS_StrictPropertyStub,
michael@0 1517 JS_EnumerateStub,
michael@0 1518 JS_ResolveStub,
michael@0 1519 JS_ConvertStub,
michael@0 1520 FinalizeStub,
michael@0 1521 nullptr, /* call */
michael@0 1522 nullptr, /* hasInstance */
michael@0 1523 nullptr, /* construct */
michael@0 1524 nullptr /* trace */
michael@0 1525 };
michael@0 1526
michael@0 1527 bool
michael@0 1528 xpc::IsOutObject(JSContext* cx, JSObject* obj)
michael@0 1529 {
michael@0 1530 return js::GetObjectJSClass(obj) == &XPCOutParamClass;
michael@0 1531 }
michael@0 1532
michael@0 1533 JSObject*
michael@0 1534 xpc::NewOutObject(JSContext* cx, JSObject* scope)
michael@0 1535 {
michael@0 1536 RootedObject global(cx, JS_GetGlobalForObject(cx, scope));
michael@0 1537 return JS_NewObject(cx, nullptr, NullPtr(), global);
michael@0 1538 }
michael@0 1539
michael@0 1540
michael@0 1541 NS_IMETHODIMP
michael@0 1542 nsXPCWrappedJSClass::DebugDump(int16_t depth)
michael@0 1543 {
michael@0 1544 #ifdef DEBUG
michael@0 1545 depth-- ;
michael@0 1546 XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %x with mRefCnt = %d", this, mRefCnt.get()));
michael@0 1547 XPC_LOG_INDENT();
michael@0 1548 char* name;
michael@0 1549 mInfo->GetName(&name);
michael@0 1550 XPC_LOG_ALWAYS(("interface name is %s", name));
michael@0 1551 if (name)
michael@0 1552 nsMemory::Free(name);
michael@0 1553 char * iid = mIID.ToString();
michael@0 1554 XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
michael@0 1555 if (iid)
michael@0 1556 NS_Free(iid);
michael@0 1557 XPC_LOG_ALWAYS(("InterfaceInfo @ %x", mInfo.get()));
michael@0 1558 uint16_t methodCount = 0;
michael@0 1559 if (depth) {
michael@0 1560 uint16_t i;
michael@0 1561 nsCOMPtr<nsIInterfaceInfo> parent;
michael@0 1562 XPC_LOG_INDENT();
michael@0 1563 mInfo->GetParent(getter_AddRefs(parent));
michael@0 1564 XPC_LOG_ALWAYS(("parent @ %x", parent.get()));
michael@0 1565 mInfo->GetMethodCount(&methodCount);
michael@0 1566 XPC_LOG_ALWAYS(("MethodCount = %d", methodCount));
michael@0 1567 mInfo->GetConstantCount(&i);
michael@0 1568 XPC_LOG_ALWAYS(("ConstantCount = %d", i));
michael@0 1569 XPC_LOG_OUTDENT();
michael@0 1570 }
michael@0 1571 XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
michael@0 1572 XPC_LOG_ALWAYS(("mDescriptors @ %x count = %d", mDescriptors, methodCount));
michael@0 1573 if (depth && mDescriptors && methodCount) {
michael@0 1574 depth--;
michael@0 1575 XPC_LOG_INDENT();
michael@0 1576 for (uint16_t i = 0; i < methodCount; i++) {
michael@0 1577 XPC_LOG_ALWAYS(("Method %d is %s%s", \
michael@0 1578 i, IsReflectable(i) ? "":" NOT ","reflectable"));
michael@0 1579 }
michael@0 1580 XPC_LOG_OUTDENT();
michael@0 1581 depth++;
michael@0 1582 }
michael@0 1583 XPC_LOG_OUTDENT();
michael@0 1584 #endif
michael@0 1585 return NS_OK;
michael@0 1586 }

mercurial