no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / js / xpconnect / src / XPCCallContext.cpp
blobb7da79ba9aa498280e2124709ac62fc8ec661206
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Call context. */
9 #include "xpcprivate.h"
10 #include "jsfriendapi.h"
11 #include "js/Object.h" // JS::GetClass, JS::GetReservedSlot
12 #include "js/Wrapper.h"
13 #include "nsContentUtils.h"
15 using namespace mozilla;
16 using namespace xpc;
17 using namespace JS;
19 static inline bool IsTearoffClass(const JSClass* clazz) {
20 return clazz == &XPC_WN_Tearoff_JSClass;
23 XPCCallContext::XPCCallContext(
24 JSContext* cx, HandleObject obj /* = nullptr */,
25 HandleObject funobj /* = nullptr */,
26 HandleId name /* = JSID_VOID */, unsigned argc /* = NO_ARGS */,
27 Value* argv /* = nullptr */, Value* rval /* = nullptr */)
28 : mState(INIT_FAILED),
29 mXPC(nsXPConnect::XPConnect()),
30 mXPCJSContext(nullptr),
31 mJSContext(cx),
32 mWrapper(nullptr),
33 mTearOff(nullptr),
34 mMember(nullptr),
35 mName(cx),
36 mStaticMemberIsLocal(false),
37 mArgc(0),
38 mArgv(nullptr),
39 mRetVal(nullptr) {
40 MOZ_ASSERT(cx);
41 MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
43 if (!mXPC) {
44 return;
47 mXPCJSContext = XPCJSContext::Get();
49 // hook into call context chain.
50 mPrevCallContext = mXPCJSContext->SetCallContext(this);
52 mState = HAVE_CONTEXT;
54 if (!obj) {
55 return;
58 mMethodIndex = 0xDEAD;
60 mState = HAVE_OBJECT;
62 mTearOff = nullptr;
64 JSObject* unwrapped =
65 js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
66 if (!unwrapped) {
67 JS_ReportErrorASCII(mJSContext,
68 "Permission denied to call method on |this|");
69 mState = INIT_FAILED;
70 return;
72 const JSClass* clasp = JS::GetClass(unwrapped);
73 if (clasp->isWrappedNative()) {
74 mWrapper = XPCWrappedNative::Get(unwrapped);
75 } else if (IsTearoffClass(clasp)) {
76 mTearOff = XPCWrappedNativeTearOff::Get(unwrapped);
77 mWrapper = XPCWrappedNative::Get(
78 &JS::GetReservedSlot(unwrapped, XPCWrappedNativeTearOff::FlatObjectSlot)
79 .toObject());
81 if (mWrapper && !mTearOff) {
82 mScriptable = mWrapper->GetScriptable();
85 if (!name.isVoid()) {
86 SetName(name);
89 if (argc != NO_ARGS) {
90 SetArgsAndResultPtr(argc, argv, rval);
93 CHECK_STATE(HAVE_OBJECT);
96 void XPCCallContext::SetName(jsid name) {
97 CHECK_STATE(HAVE_OBJECT);
99 mName = name;
101 if (mTearOff) {
102 mSet = nullptr;
103 mInterface = mTearOff->GetInterface();
104 mMember = mInterface->FindMember(mName);
105 mStaticMemberIsLocal = true;
106 if (mMember && !mMember->IsConstant()) {
107 mMethodIndex = mMember->GetIndex();
109 } else {
110 mSet = mWrapper ? mWrapper->GetSet() : nullptr;
112 if (mSet &&
113 mSet->FindMember(
114 mName, &mMember, &mInterface,
115 mWrapper->HasProto() ? mWrapper->GetProto()->GetSet() : nullptr,
116 &mStaticMemberIsLocal)) {
117 if (mMember && !mMember->IsConstant()) {
118 mMethodIndex = mMember->GetIndex();
120 } else {
121 mMember = nullptr;
122 mInterface = nullptr;
123 mStaticMemberIsLocal = false;
127 mState = HAVE_NAME;
130 void XPCCallContext::SetCallInfo(XPCNativeInterface* iface,
131 XPCNativeMember* member, bool isSetter) {
132 CHECK_STATE(HAVE_CONTEXT);
134 // We are going straight to the method info and need not do a lookup
135 // by id.
137 // don't be tricked if method is called with wrong 'this'
138 if (mTearOff && mTearOff->GetInterface() != iface) {
139 mTearOff = nullptr;
142 mSet = nullptr;
143 mInterface = iface;
144 mMember = member;
145 mMethodIndex = mMember->GetIndex() + (isSetter ? 1 : 0);
146 mName = mMember->GetName();
148 if (mState < HAVE_NAME) {
149 mState = HAVE_NAME;
153 void XPCCallContext::SetArgsAndResultPtr(unsigned argc, Value* argv,
154 Value* rval) {
155 CHECK_STATE(HAVE_OBJECT);
157 if (mState < HAVE_NAME) {
158 mSet = nullptr;
159 mInterface = nullptr;
160 mMember = nullptr;
161 mStaticMemberIsLocal = false;
164 mArgc = argc;
165 mArgv = argv;
166 mRetVal = rval;
168 mState = HAVE_ARGS;
171 nsresult XPCCallContext::CanCallNow() {
172 nsresult rv;
174 if (!HasInterfaceAndMember()) {
175 return NS_ERROR_UNEXPECTED;
177 if (mState < HAVE_ARGS) {
178 return NS_ERROR_UNEXPECTED;
181 if (!mTearOff) {
182 mTearOff = mWrapper->FindTearOff(mJSContext, mInterface, false, &rv);
183 if (!mTearOff || mTearOff->GetInterface() != mInterface) {
184 mTearOff = nullptr;
185 return NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED;
189 // Refresh in case FindTearOff extended the set
190 mSet = mWrapper->GetSet();
192 mState = READY_TO_CALL;
193 return NS_OK;
196 void XPCCallContext::SystemIsBeingShutDown() {
197 // XXX This is pretty questionable since the per thread cleanup stuff
198 // can be making this call on one thread for call contexts on another
199 // thread.
200 NS_WARNING(
201 "Shutting Down XPConnect even through there is a live XPCCallContext");
202 mXPCJSContext = nullptr;
203 mState = SYSTEM_SHUTDOWN;
204 mSet = nullptr;
205 mInterface = nullptr;
207 if (mPrevCallContext) {
208 mPrevCallContext->SystemIsBeingShutDown();
212 XPCCallContext::~XPCCallContext() {
213 if (mXPCJSContext) {
214 DebugOnly<XPCCallContext*> old =
215 mXPCJSContext->SetCallContext(mPrevCallContext);
216 MOZ_ASSERT(old == this, "bad pop from per thread data");