summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/XPCCallContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/src/XPCCallContext.cpp')
-rw-r--r--js/xpconnect/src/XPCCallContext.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp
new file mode 100644
index 000000000..22081e3cf
--- /dev/null
+++ b/js/xpconnect/src/XPCCallContext.cpp
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* 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/. */
+
+/* Call context. */
+
+#include "xpcprivate.h"
+#include "jswrapper.h"
+#include "jsfriendapi.h"
+#include "nsContentUtils.h"
+
+using namespace mozilla;
+using namespace xpc;
+using namespace JS;
+
+#define IS_TEAROFF_CLASS(clazz) ((clazz) == &XPC_WN_Tearoff_JSClass)
+
+XPCCallContext::XPCCallContext(JSContext* cx,
+ HandleObject obj /* = nullptr */,
+ HandleObject funobj /* = nullptr */,
+ HandleId name /* = JSID_VOID */,
+ unsigned argc /* = NO_ARGS */,
+ Value* argv /* = nullptr */,
+ Value* rval /* = nullptr */)
+ : mAr(cx),
+ mState(INIT_FAILED),
+ mXPC(nsXPConnect::XPConnect()),
+ mXPCJSContext(nullptr),
+ mJSContext(cx),
+ mWrapper(nullptr),
+ mTearOff(nullptr),
+ mName(cx)
+{
+ MOZ_ASSERT(cx);
+ MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
+
+ if (!mXPC)
+ return;
+
+ mXPCJSContext = XPCJSContext::Get();
+
+ // hook into call context chain.
+ mPrevCallContext = mXPCJSContext->SetCallContext(this);
+
+ mState = HAVE_CONTEXT;
+
+ if (!obj)
+ return;
+
+ mMethodIndex = 0xDEAD;
+
+ mState = HAVE_OBJECT;
+
+ mTearOff = nullptr;
+
+ JSObject* unwrapped = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
+ if (!unwrapped) {
+ JS_ReportErrorASCII(mJSContext, "Permission denied to call method on |this|");
+ mState = INIT_FAILED;
+ return;
+ }
+ const js::Class* clasp = js::GetObjectClass(unwrapped);
+ if (IS_WN_CLASS(clasp)) {
+ mWrapper = XPCWrappedNative::Get(unwrapped);
+ } else if (IS_TEAROFF_CLASS(clasp)) {
+ mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped);
+ mWrapper = XPCWrappedNative::Get(
+ &js::GetReservedSlot(unwrapped,
+ XPC_WN_TEAROFF_FLAT_OBJECT_SLOT).toObject());
+ }
+ if (mWrapper) {
+ if (mTearOff)
+ mScriptableInfo = nullptr;
+ else
+ mScriptableInfo = mWrapper->GetScriptableInfo();
+ }
+
+ if (!JSID_IS_VOID(name))
+ SetName(name);
+
+ if (argc != NO_ARGS)
+ SetArgsAndResultPtr(argc, argv, rval);
+
+ CHECK_STATE(HAVE_OBJECT);
+}
+
+void
+XPCCallContext::SetName(jsid name)
+{
+ CHECK_STATE(HAVE_OBJECT);
+
+ mName = name;
+
+ if (mTearOff) {
+ mSet = nullptr;
+ mInterface = mTearOff->GetInterface();
+ mMember = mInterface->FindMember(mName);
+ mStaticMemberIsLocal = true;
+ if (mMember && !mMember->IsConstant())
+ mMethodIndex = mMember->GetIndex();
+ } else {
+ mSet = mWrapper ? mWrapper->GetSet() : nullptr;
+
+ if (mSet &&
+ mSet->FindMember(mName, &mMember, &mInterface,
+ mWrapper->HasProto() ?
+ mWrapper->GetProto()->GetSet() :
+ nullptr,
+ &mStaticMemberIsLocal)) {
+ if (mMember && !mMember->IsConstant())
+ mMethodIndex = mMember->GetIndex();
+ } else {
+ mMember = nullptr;
+ mInterface = nullptr;
+ mStaticMemberIsLocal = false;
+ }
+ }
+
+ mState = HAVE_NAME;
+}
+
+void
+XPCCallContext::SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
+ bool isSetter)
+{
+ CHECK_STATE(HAVE_CONTEXT);
+
+ // We are going straight to the method info and need not do a lookup
+ // by id.
+
+ // don't be tricked if method is called with wrong 'this'
+ if (mTearOff && mTearOff->GetInterface() != iface)
+ mTearOff = nullptr;
+
+ mSet = nullptr;
+ mInterface = iface;
+ mMember = member;
+ mMethodIndex = mMember->GetIndex() + (isSetter ? 1 : 0);
+ mName = mMember->GetName();
+
+ if (mState < HAVE_NAME)
+ mState = HAVE_NAME;
+}
+
+void
+XPCCallContext::SetArgsAndResultPtr(unsigned argc,
+ Value* argv,
+ Value* rval)
+{
+ CHECK_STATE(HAVE_OBJECT);
+
+ if (mState < HAVE_NAME) {
+ mSet = nullptr;
+ mInterface = nullptr;
+ mMember = nullptr;
+ mStaticMemberIsLocal = false;
+ }
+
+ mArgc = argc;
+ mArgv = argv;
+ mRetVal = rval;
+
+ mState = HAVE_ARGS;
+}
+
+nsresult
+XPCCallContext::CanCallNow()
+{
+ nsresult rv;
+
+ if (!HasInterfaceAndMember())
+ return NS_ERROR_UNEXPECTED;
+ if (mState < HAVE_ARGS)
+ return NS_ERROR_UNEXPECTED;
+
+ if (!mTearOff) {
+ mTearOff = mWrapper->FindTearOff(mInterface, false, &rv);
+ if (!mTearOff || mTearOff->GetInterface() != mInterface) {
+ mTearOff = nullptr;
+ return NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ // Refresh in case FindTearOff extended the set
+ mSet = mWrapper->GetSet();
+
+ mState = READY_TO_CALL;
+ return NS_OK;
+}
+
+void
+XPCCallContext::SystemIsBeingShutDown()
+{
+ // XXX This is pretty questionable since the per thread cleanup stuff
+ // can be making this call on one thread for call contexts on another
+ // thread.
+ NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
+ mXPCJSContext = nullptr;
+ mState = SYSTEM_SHUTDOWN;
+ mSet = nullptr;
+ mInterface = nullptr;
+
+ if (mPrevCallContext)
+ mPrevCallContext->SystemIsBeingShutDown();
+}
+
+XPCCallContext::~XPCCallContext()
+{
+ if (mXPCJSContext) {
+ DebugOnly<XPCCallContext*> old = mXPCJSContext->SetCallContext(mPrevCallContext);
+ MOZ_ASSERT(old == this, "bad pop from per thread data");
+ }
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetCallee(nsISupports * *aCallee)
+{
+ nsCOMPtr<nsISupports> rval = mWrapper ? mWrapper->GetIdentityObject() : nullptr;
+ rval.forget(aCallee);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetCalleeMethodIndex(uint16_t* aCalleeMethodIndex)
+{
+ *aCalleeMethodIndex = mMethodIndex;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetCalleeInterface(nsIInterfaceInfo * *aCalleeInterface)
+{
+ nsCOMPtr<nsIInterfaceInfo> rval = mInterface->GetInterfaceInfo();
+ rval.forget(aCalleeInterface);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetCalleeClassInfo(nsIClassInfo * *aCalleeClassInfo)
+{
+ nsCOMPtr<nsIClassInfo> rval = mWrapper ? mWrapper->GetClassInfo() : nullptr;
+ rval.forget(aCalleeClassInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetJSContext(JSContext * *aJSContext)
+{
+ JS_AbortIfWrongThread(mJSContext);
+ *aJSContext = mJSContext;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetArgc(uint32_t* aArgc)
+{
+ *aArgc = (uint32_t) mArgc;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetArgvPtr(Value** aArgvPtr)
+{
+ *aArgvPtr = mArgv;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+XPCCallContext::GetPreviousCallContext(nsAXPCNativeCallContext** aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+ *aResult = GetPrevCallContext();
+ return NS_OK;
+}