gecko-dev/dom/base/MozQueryInterface.cpp
Nika Layzell 11b083d72c Bug 1477432 - Part 9: Switch to using plain JS objects for nsIJS[IC]ID, r=mccr8
This is a complete rewrite of the interface while maintaining the same APIs.
Each ID is fully-contained within a single object, does not require a finalizer,
and is cheap to create.

Beyond using reserved slots, this code avoids using custom ClassOps, instead
preferring Symbol.hasInstance and eager constants.

One major change which occurred in this patch was the move from storing a nsCID
to storing the ContractID for JSCID objects. This eliminates the need for the
'refreshCID' method, and hopefully shouldn't have performance implications.

If we discover that there are performance problems there, we can look into
stashing the CID, and re-introduce 'refreshCID', despite its surprising
behaviour.

Differential Revision: https://phabricator.services.mozilla.com/D2286
2018-11-16 17:27:44 -05:00

103 lines
2.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ChromeUtils.h"
#include "MozQueryInterface.h"
#include "nsIException.h"
#include <string.h>
#include "jsapi.h"
#include "xpcpublic.h"
namespace mozilla {
namespace dom {
constexpr size_t IID_SIZE = sizeof(nsIID);
static_assert(IID_SIZE == 16,
"Size of nsID struct changed. Please ensure this code is still valid.");
static int
CompareIIDs(const nsIID& aA, const nsIID &aB)
{
return memcmp((void*)&aA.m0, (void*)&aB.m0, IID_SIZE);
}
/* static */
MozQueryInterface*
ChromeUtils::GenerateQI(const GlobalObject& aGlobal,
const Sequence<JS::Value>& aInterfaces,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
nsTArray<nsIID> ifaces;
JS::RootedValue iface(cx);
for (uint32_t idx = 0; idx < aInterfaces.Length(); ++idx) {
iface = aInterfaces[idx];
// Handle ID objects
if (Maybe<nsID> id = xpc::JSValue2ID(cx, iface)) {
ifaces.AppendElement(*id);
continue;
}
// Accept string valued names
if (iface.isString()) {
JS::UniqueChars name = JS_EncodeStringToLatin1(cx, iface.toString());
const nsXPTInterfaceInfo* iinfo = nsXPTInterfaceInfo::ByName(name.get());
if (iinfo) {
ifaces.AppendElement(iinfo->IID());
continue;
}
}
// NOTE: We ignore unknown interfaces here because in some cases we try to
// pass them in to support multiple platforms.
}
MOZ_ASSERT(!ifaces.Contains(NS_GET_IID(nsISupports), CompareIIDs));
ifaces.AppendElement(NS_GET_IID(nsISupports));
ifaces.Sort(CompareIIDs);
return new MozQueryInterface(std::move(ifaces));
}
bool
MozQueryInterface::QueriesTo(const nsIID& aIID) const
{
return mInterfaces.ContainsSorted(aIID, CompareIIDs);
}
void
MozQueryInterface::LegacyCall(JSContext* cx, JS::Handle<JS::Value> thisv,
JS::Handle<JS::Value> aIID,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) const
{
Maybe<nsID> id = xpc::JSValue2ID(cx, aIID);
if (id && QueriesTo(*id)) {
aResult.set(thisv);
} else {
aRv.Throw(NS_ERROR_NO_INTERFACE);
}
}
bool
MozQueryInterface::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
{
return MozQueryInterface_Binding::Wrap(aCx, this, aGivenProto, aReflector);
}
} // namespace dom
} // namespace mozilla