Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/bindings/BindingUtils.cpp
Line
Count
Source (jump to first uncovered line)
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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "BindingUtils.h"
8
9
#include <algorithm>
10
#include <stdarg.h>
11
12
#include "mozilla/Assertions.h"
13
#include "mozilla/DebugOnly.h"
14
#include "mozilla/FloatingPoint.h"
15
#include "mozilla/Preferences.h"
16
#include "mozilla/Unused.h"
17
#include "mozilla/UseCounter.h"
18
19
#include "AccessCheck.h"
20
#include "js/JSON.h"
21
#include "js/StableStringChars.h"
22
#include "jsfriendapi.h"
23
#include "nsContentCreatorFunctions.h"
24
#include "nsContentUtils.h"
25
#include "nsGlobalWindow.h"
26
#include "nsHTMLTags.h"
27
#include "nsIDocShell.h"
28
#include "nsIDOMGlobalPropertyInitializer.h"
29
#include "nsINode.h"
30
#include "nsIPermissionManager.h"
31
#include "nsIPrincipal.h"
32
#include "nsIXPConnect.h"
33
#include "nsUTF8Utils.h"
34
#include "WorkerPrivate.h"
35
#include "WorkerRunnable.h"
36
#include "WrapperFactory.h"
37
#include "xpcprivate.h"
38
#include "XrayWrapper.h"
39
#include "nsPrintfCString.h"
40
#include "mozilla/Sprintf.h"
41
#include "nsGlobalWindow.h"
42
#include "nsReadableUtils.h"
43
44
#include "mozilla/dom/ScriptSettings.h"
45
#include "mozilla/dom/CustomElementRegistry.h"
46
#include "mozilla/dom/DOMException.h"
47
#include "mozilla/dom/ElementBinding.h"
48
#include "mozilla/dom/HTMLObjectElement.h"
49
#include "mozilla/dom/HTMLObjectElementBinding.h"
50
#include "mozilla/dom/HTMLEmbedElement.h"
51
#include "mozilla/dom/HTMLElementBinding.h"
52
#include "mozilla/dom/HTMLEmbedElementBinding.h"
53
#include "mozilla/dom/XULElementBinding.h"
54
#include "mozilla/dom/XULFrameElementBinding.h"
55
#include "mozilla/dom/XULMenuElementBinding.h"
56
#include "mozilla/dom/XULPopupElementBinding.h"
57
#include "mozilla/dom/Promise.h"
58
#include "mozilla/dom/ResolveSystemBinding.h"
59
#include "mozilla/dom/WebIDLGlobalNameHash.h"
60
#include "mozilla/dom/WorkerPrivate.h"
61
#include "mozilla/dom/WorkerScope.h"
62
#include "mozilla/dom/XrayExpandoClass.h"
63
#include "mozilla/dom/XULScrollElementBinding.h"
64
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
65
#include "ipc/ErrorIPCUtils.h"
66
#include "mozilla/UseCounter.h"
67
#include "mozilla/dom/DocGroup.h"
68
#include "nsXULElement.h"
69
70
namespace mozilla {
71
namespace dom {
72
73
// Forward declare GetConstructorObject methods.
74
#define HTML_TAG(_tag, _classname, _interfacename)                             \
75
namespace HTML##_interfacename##Element_Binding {                               \
76
  JSObject* GetConstructorObject(JSContext*);                                  \
77
}
78
#define HTML_OTHER(_tag)
79
#include "nsHTMLTagList.h"
80
#undef HTML_TAG
81
#undef HTML_OTHER
82
83
typedef JSObject* (*constructorGetterCallback)(JSContext*);
84
85
// Mapping of html tag and GetConstructorObject methods.
86
#define HTML_TAG(_tag, _classname, _interfacename) HTML##_interfacename##Element_Binding::GetConstructorObject,
87
#define HTML_OTHER(_tag) nullptr,
88
// We use eHTMLTag_foo (where foo is the tag) which is defined in nsHTMLTags.h
89
// to index into this array.
90
static const constructorGetterCallback sConstructorGetterCallback[] = {
91
  HTMLUnknownElement_Binding::GetConstructorObject,
92
#include "nsHTMLTagList.h"
93
#undef HTML_TAG
94
#undef HTML_OTHER
95
};
96
97
const JSErrorFormatString ErrorFormatString[] = {
98
#define MSG_DEF(_name, _argc, _exn, _str) \
99
  { #_name, _str, _argc, _exn },
100
#include "mozilla/dom/Errors.msg"
101
#undef MSG_DEF
102
};
103
104
#define MSG_DEF(_name, _argc, _exn, _str) \
105
  static_assert(_argc < JS::MaxNumErrorArguments, \
106
                #_name " must only have as many error arguments as the JS engine can support");
107
#include "mozilla/dom/Errors.msg"
108
#undef MSG_DEF
109
110
const JSErrorFormatString*
111
GetErrorMessage(void* aUserRef, const unsigned aErrorNumber)
112
0
{
113
0
  MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString));
114
0
  return &ErrorFormatString[aErrorNumber];
115
0
}
116
117
uint16_t
118
GetErrorArgCount(const ErrNum aErrorNumber)
119
0
{
120
0
  return GetErrorMessage(nullptr, aErrorNumber)->argCount;
121
0
}
122
123
void
124
binding_detail::ThrowErrorMessage(JSContext* aCx, const unsigned aErrorNumber, ...)
125
0
{
126
0
  va_list ap;
127
0
  va_start(ap, aErrorNumber);
128
0
  JS_ReportErrorNumberUTF8VA(aCx, GetErrorMessage, nullptr, aErrorNumber, ap);
129
0
  va_end(ap);
130
0
}
131
132
bool
133
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
134
                 bool aSecurityError, const char* aInterfaceName)
135
0
{
136
0
  NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
137
0
  // This should only be called for DOM methods/getters/setters, which
138
0
  // are JSNative-backed functions, so we can assume that
139
0
  // JS_ValueToFunction and JS_GetFunctionDisplayId will both return
140
0
  // non-null and that JS_GetStringCharsZ returns non-null.
141
0
  JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
142
0
  MOZ_ASSERT(func);
143
0
  JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
144
0
  MOZ_ASSERT(funcName);
145
0
  nsAutoJSString funcNameStr;
146
0
  if (!funcNameStr.init(aCx, funcName)) {
147
0
    return false;
148
0
  }
149
0
  const ErrNum errorNumber = aSecurityError ?
150
0
                             MSG_METHOD_THIS_UNWRAPPING_DENIED :
151
0
                             MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
152
0
  MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2);
153
0
  JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
154
0
                         static_cast<unsigned>(errorNumber),
155
0
                         funcNameStr.get(), ifaceName.get());
156
0
  return false;
157
0
}
158
159
bool
160
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
161
                 bool aSecurityError,
162
                 prototypes::ID aProtoId)
163
0
{
164
0
  return ThrowInvalidThis(aCx, aArgs, aSecurityError,
165
0
                          NamesOfInterfacesWithProtos(aProtoId));
166
0
}
167
168
bool
169
ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
170
0
{
171
0
  nsPrintfCString errorMessage("%s attribute setter",
172
0
                               NamesOfInterfacesWithProtos(aProtoId));
173
0
  return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
174
0
}
175
176
} // namespace dom
177
178
namespace binding_danger {
179
180
template<typename CleanupPolicy>
181
struct TErrorResult<CleanupPolicy>::Message {
182
  Message()
183
    : mErrorNumber(dom::Err_Limit)
184
0
  {
185
0
    MOZ_COUNT_CTOR(TErrorResult::Message);
186
0
  }
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::Message::Message()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::Message::Message()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::Message::Message()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::Message::Message()
187
0
  ~Message() { MOZ_COUNT_DTOR(TErrorResult::Message); }
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::Message::~Message()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::Message::~Message()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::Message::~Message()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::Message::~Message()
188
189
  nsTArray<nsString> mArgs;
190
  dom::ErrNum mErrorNumber;
191
192
  bool HasCorrectNumberOfArguments()
193
0
  {
194
0
    return GetErrorArgCount(mErrorNumber) == mArgs.Length();
195
0
  }
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::Message::HasCorrectNumberOfArguments()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::Message::HasCorrectNumberOfArguments()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::Message::HasCorrectNumberOfArguments()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::Message::HasCorrectNumberOfArguments()
196
197
  bool operator==(const TErrorResult<CleanupPolicy>::Message& aRight) const
198
0
  {
199
0
    return mErrorNumber == aRight.mErrorNumber &&
200
0
           mArgs == aRight.mArgs;
201
0
  }
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::Message::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::Message const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::Message::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::Message const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::Message::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::Message const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::Message::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::Message const&) const
202
};
203
204
template<typename CleanupPolicy>
205
nsTArray<nsString>&
206
TErrorResult<CleanupPolicy>::CreateErrorMessageHelper(const dom::ErrNum errorNumber,
207
                                                      nsresult errorType)
208
0
{
209
0
  AssertInOwningThread();
210
0
  mResult = errorType;
211
0
212
0
  Message* message = InitMessage(new Message());
213
0
  message->mErrorNumber = errorNumber;
214
0
  return message->mArgs;
215
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::CreateErrorMessageHelper(mozilla::dom::ErrNum, nsresult)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::CreateErrorMessageHelper(mozilla::dom::ErrNum, nsresult)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::CreateErrorMessageHelper(mozilla::dom::ErrNum, nsresult)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::CreateErrorMessageHelper(mozilla::dom::ErrNum, nsresult)
216
217
template<typename CleanupPolicy>
218
void
219
TErrorResult<CleanupPolicy>::SerializeMessage(IPC::Message* aMsg) const
220
0
{
221
0
  using namespace IPC;
222
0
  AssertInOwningThread();
223
0
  MOZ_ASSERT(mUnionState == HasMessage);
224
0
  MOZ_ASSERT(mExtra.mMessage);
225
0
  WriteParam(aMsg, mExtra.mMessage->mArgs);
226
0
  WriteParam(aMsg, mExtra.mMessage->mErrorNumber);
227
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SerializeMessage(IPC::Message*) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SerializeMessage(IPC::Message*) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SerializeMessage(IPC::Message*) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SerializeMessage(IPC::Message*) const
228
229
template<typename CleanupPolicy>
230
bool
231
TErrorResult<CleanupPolicy>::DeserializeMessage(const IPC::Message* aMsg,
232
                                                PickleIterator* aIter)
233
0
{
234
0
  using namespace IPC;
235
0
  AssertInOwningThread();
236
0
  nsAutoPtr<Message> readMessage(new Message());
237
0
  if (!ReadParam(aMsg, aIter, &readMessage->mArgs) ||
238
0
      !ReadParam(aMsg, aIter, &readMessage->mErrorNumber)) {
239
0
    return false;
240
0
  }
241
0
  if (!readMessage->HasCorrectNumberOfArguments()) {
242
0
    return false;
243
0
  }
244
0
245
0
  MOZ_ASSERT(mUnionState == HasNothing);
246
0
  InitMessage(readMessage.forget());
247
#ifdef DEBUG
248
  mUnionState = HasMessage;
249
#endif // DEBUG
250
  return true;
251
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::DeserializeMessage(IPC::Message const*, PickleIterator*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::DeserializeMessage(IPC::Message const*, PickleIterator*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::DeserializeMessage(IPC::Message const*, PickleIterator*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::DeserializeMessage(IPC::Message const*, PickleIterator*)
252
253
template<typename CleanupPolicy>
254
void
255
TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx)
256
0
{
257
0
  AssertInOwningThread();
258
0
  MOZ_ASSERT(mUnionState == HasMessage);
259
0
  MOZ_ASSERT(mExtra.mMessage,
260
0
             "SetPendingExceptionWithMessage() can be called only once");
261
0
262
0
  Message* message = mExtra.mMessage;
263
0
  MOZ_RELEASE_ASSERT(message->HasCorrectNumberOfArguments());
264
0
  const uint32_t argCount = message->mArgs.Length();
265
0
  const char16_t* args[JS::MaxNumErrorArguments + 1];
266
0
  for (uint32_t i = 0; i < argCount; ++i) {
267
0
    args[i] = message->mArgs.ElementAt(i).get();
268
0
  }
269
0
  args[argCount] = nullptr;
270
0
271
0
  JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
272
0
                              static_cast<unsigned>(message->mErrorNumber),
273
0
                              argCount > 0 ? args : nullptr);
274
0
275
0
  ClearMessage();
276
0
  mResult = NS_OK;
277
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SetPendingExceptionWithMessage(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SetPendingExceptionWithMessage(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SetPendingExceptionWithMessage(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SetPendingExceptionWithMessage(JSContext*)
278
279
template<typename CleanupPolicy>
280
void
281
TErrorResult<CleanupPolicy>::ClearMessage()
282
0
{
283
0
  AssertInOwningThread();
284
0
  MOZ_ASSERT(IsErrorWithMessage());
285
0
  MOZ_ASSERT(mUnionState == HasMessage);
286
0
  delete mExtra.mMessage;
287
0
  mExtra.mMessage = nullptr;
288
#ifdef DEBUG
289
  mUnionState = HasNothing;
290
#endif // DEBUG
291
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::ClearMessage()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::ClearMessage()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::ClearMessage()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::ClearMessage()
292
293
template<typename CleanupPolicy>
294
void
295
TErrorResult<CleanupPolicy>::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
296
0
{
297
0
  AssertInOwningThread();
298
0
  MOZ_ASSERT(mMightHaveUnreportedJSException,
299
0
             "Why didn't you tell us you planned to throw a JS exception?");
300
0
301
0
  ClearUnionData();
302
0
303
0
  // Make sure mExtra.mJSException is initialized _before_ we try to root it.
304
0
  // But don't set it to exn yet, because we don't want to do that until after
305
0
  // we root.
306
0
  JS::Value& exc = InitJSException();
307
0
  if (!js::AddRawValueRoot(cx, &exc, "TErrorResult::mExtra::mJSException")) {
308
0
    // Don't use NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION, because that
309
0
    // indicates we have in fact rooted mExtra.mJSException.
310
0
    mResult = NS_ERROR_OUT_OF_MEMORY;
311
0
  } else {
312
0
    exc = exn;
313
0
    mResult = NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION;
314
#ifdef DEBUG
315
    mUnionState = HasJSException;
316
#endif // DEBUG
317
  }
318
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::ThrowJSException(JSContext*, JS::Handle<JS::Value>)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::ThrowJSException(JSContext*, JS::Handle<JS::Value>)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::ThrowJSException(JSContext*, JS::Handle<JS::Value>)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::ThrowJSException(JSContext*, JS::Handle<JS::Value>)
319
320
template<typename CleanupPolicy>
321
void
322
TErrorResult<CleanupPolicy>::SetPendingJSException(JSContext* cx)
323
0
{
324
0
  AssertInOwningThread();
325
0
  MOZ_ASSERT(!mMightHaveUnreportedJSException,
326
0
             "Why didn't you tell us you planned to handle JS exceptions?");
327
0
  MOZ_ASSERT(mUnionState == HasJSException);
328
0
329
0
  JS::Rooted<JS::Value> exception(cx, mExtra.mJSException);
330
0
  if (JS_WrapValue(cx, &exception)) {
331
0
    JS_SetPendingException(cx, exception);
332
0
  }
333
0
  mExtra.mJSException = exception;
334
0
  // If JS_WrapValue failed, not much we can do about it...  No matter
335
0
  // what, go ahead and unroot mExtra.mJSException.
336
0
  js::RemoveRawValueRoot(cx, &mExtra.mJSException);
337
0
338
0
  mResult = NS_OK;
339
#ifdef DEBUG
340
  mUnionState = HasNothing;
341
#endif // DEBUG
342
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SetPendingJSException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SetPendingJSException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SetPendingJSException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SetPendingJSException(JSContext*)
343
344
template<typename CleanupPolicy>
345
struct TErrorResult<CleanupPolicy>::DOMExceptionInfo {
346
  DOMExceptionInfo(nsresult rv, const nsACString& message)
347
    : mMessage(message)
348
    , mRv(rv)
349
0
  {}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::DOMExceptionInfo::DOMExceptionInfo(nsresult, nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::DOMExceptionInfo::DOMExceptionInfo(nsresult, nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::DOMExceptionInfo::DOMExceptionInfo(nsresult, nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::DOMExceptionInfo::DOMExceptionInfo(nsresult, nsTSubstring<char> const&)
350
351
  nsCString mMessage;
352
  nsresult mRv;
353
354
  bool operator==(const TErrorResult<CleanupPolicy>::DOMExceptionInfo& aRight) const
355
0
  {
356
0
    return mRv == aRight.mRv &&
357
0
           mMessage == aRight.mMessage;
358
0
  }
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::DOMExceptionInfo::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::DOMExceptionInfo const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::DOMExceptionInfo::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::DOMExceptionInfo const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::DOMExceptionInfo::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::DOMExceptionInfo const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::DOMExceptionInfo::operator==(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::DOMExceptionInfo const&) const
359
};
360
361
template<typename CleanupPolicy>
362
void
363
TErrorResult<CleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message* aMsg) const
364
0
{
365
0
  using namespace IPC;
366
0
  AssertInOwningThread();
367
0
  MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
368
0
  MOZ_ASSERT(mExtra.mDOMExceptionInfo);
369
0
  WriteParam(aMsg, mExtra.mDOMExceptionInfo->mMessage);
370
0
  WriteParam(aMsg, mExtra.mDOMExceptionInfo->mRv);
371
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message*) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message*) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message*) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SerializeDOMExceptionInfo(IPC::Message*) const
372
373
template<typename CleanupPolicy>
374
bool
375
TErrorResult<CleanupPolicy>::DeserializeDOMExceptionInfo(const IPC::Message* aMsg,
376
                                                         PickleIterator* aIter)
377
0
{
378
0
  using namespace IPC;
379
0
  AssertInOwningThread();
380
0
  nsCString message;
381
0
  nsresult rv;
382
0
  if (!ReadParam(aMsg, aIter, &message) ||
383
0
      !ReadParam(aMsg, aIter, &rv)) {
384
0
    return false;
385
0
  }
386
0
387
0
  MOZ_ASSERT(mUnionState == HasNothing);
388
0
  MOZ_ASSERT(IsDOMException());
389
0
  InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
390
#ifdef DEBUG
391
  mUnionState = HasDOMExceptionInfo;
392
#endif // DEBUG
393
  return true;
394
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::DeserializeDOMExceptionInfo(IPC::Message const*, PickleIterator*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::DeserializeDOMExceptionInfo(IPC::Message const*, PickleIterator*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::DeserializeDOMExceptionInfo(IPC::Message const*, PickleIterator*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::DeserializeDOMExceptionInfo(IPC::Message const*, PickleIterator*)
395
396
template<typename CleanupPolicy>
397
void
398
TErrorResult<CleanupPolicy>::ThrowDOMException(nsresult rv,
399
                                               const nsACString& message)
400
0
{
401
0
  AssertInOwningThread();
402
0
  ClearUnionData();
403
0
404
0
  mResult = NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION;
405
0
  InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
406
#ifdef DEBUG
407
  mUnionState = HasDOMExceptionInfo;
408
#endif
409
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::ThrowDOMException(nsresult, nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::ThrowDOMException(nsresult, nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::ThrowDOMException(nsresult, nsTSubstring<char> const&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::ThrowDOMException(nsresult, nsTSubstring<char> const&)
410
411
template<typename CleanupPolicy>
412
void
413
TErrorResult<CleanupPolicy>::SetPendingDOMException(JSContext* cx)
414
0
{
415
0
  AssertInOwningThread();
416
0
  MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
417
0
  MOZ_ASSERT(mExtra.mDOMExceptionInfo,
418
0
             "SetPendingDOMException() can be called only once");
419
0
420
0
  dom::Throw(cx, mExtra.mDOMExceptionInfo->mRv,
421
0
             mExtra.mDOMExceptionInfo->mMessage);
422
0
423
0
  ClearDOMExceptionInfo();
424
0
  mResult = NS_OK;
425
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SetPendingDOMException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SetPendingDOMException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SetPendingDOMException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SetPendingDOMException(JSContext*)
426
427
template<typename CleanupPolicy>
428
void
429
TErrorResult<CleanupPolicy>::ClearDOMExceptionInfo()
430
0
{
431
0
  AssertInOwningThread();
432
0
  MOZ_ASSERT(IsDOMException());
433
0
  MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
434
0
  delete mExtra.mDOMExceptionInfo;
435
0
  mExtra.mDOMExceptionInfo = nullptr;
436
#ifdef DEBUG
437
  mUnionState = HasNothing;
438
#endif // DEBUG
439
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::ClearDOMExceptionInfo()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::ClearDOMExceptionInfo()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::ClearDOMExceptionInfo()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::ClearDOMExceptionInfo()
440
441
template<typename CleanupPolicy>
442
void
443
TErrorResult<CleanupPolicy>::ClearUnionData()
444
0
{
445
0
  AssertInOwningThread();
446
0
  if (IsJSException()) {
447
0
    JSContext* cx = dom::danger::GetJSContext();
448
0
    MOZ_ASSERT(cx);
449
0
    mExtra.mJSException.setUndefined();
450
0
    js::RemoveRawValueRoot(cx, &mExtra.mJSException);
451
#ifdef DEBUG
452
    mUnionState = HasNothing;
453
#endif // DEBUG
454
0
  } else if (IsErrorWithMessage()) {
455
0
    ClearMessage();
456
0
  } else if (IsDOMException()) {
457
0
    ClearDOMExceptionInfo();
458
0
  }
459
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::ClearUnionData()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::ClearUnionData()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::ClearUnionData()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::ClearUnionData()
460
461
template<typename CleanupPolicy>
462
void
463
TErrorResult<CleanupPolicy>::SetPendingGenericErrorException(JSContext* cx)
464
0
{
465
0
  AssertInOwningThread();
466
0
  MOZ_ASSERT(!IsErrorWithMessage());
467
0
  MOZ_ASSERT(!IsJSException());
468
0
  MOZ_ASSERT(!IsDOMException());
469
0
  dom::Throw(cx, ErrorCode());
470
0
  mResult = NS_OK;
471
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SetPendingGenericErrorException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SetPendingGenericErrorException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SetPendingGenericErrorException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SetPendingGenericErrorException(JSContext*)
472
473
template<typename CleanupPolicy>
474
TErrorResult<CleanupPolicy>&
475
TErrorResult<CleanupPolicy>::operator=(TErrorResult<CleanupPolicy>&& aRHS)
476
0
{
477
0
  AssertInOwningThread();
478
0
  aRHS.AssertInOwningThread();
479
0
  // Clear out any union members we may have right now, before we
480
0
  // start writing to it.
481
0
  ClearUnionData();
482
0
483
#ifdef DEBUG
484
  mMightHaveUnreportedJSException = aRHS.mMightHaveUnreportedJSException;
485
  aRHS.mMightHaveUnreportedJSException = false;
486
#endif
487
0
  if (aRHS.IsErrorWithMessage()) {
488
0
    InitMessage(aRHS.mExtra.mMessage);
489
0
    aRHS.mExtra.mMessage = nullptr;
490
0
  } else if (aRHS.IsJSException()) {
491
0
    JSContext* cx = dom::danger::GetJSContext();
492
0
    MOZ_ASSERT(cx);
493
0
    JS::Value& exn = InitJSException();
494
0
    if (!js::AddRawValueRoot(cx, &exn,
495
0
                             "TErrorResult::mExtra::mJSException")) {
496
0
      MOZ_CRASH("Could not root mExtra.mJSException, we're about to OOM");
497
0
    }
498
0
    mExtra.mJSException = aRHS.mExtra.mJSException;
499
0
    aRHS.mExtra.mJSException.setUndefined();
500
0
    js::RemoveRawValueRoot(cx, &aRHS.mExtra.mJSException);
501
0
  } else if (aRHS.IsDOMException()) {
502
0
    InitDOMExceptionInfo(aRHS.mExtra.mDOMExceptionInfo);
503
0
    aRHS.mExtra.mDOMExceptionInfo = nullptr;
504
0
  } else {
505
0
    // Null out the union on both sides for hygiene purposes.  This is purely
506
0
    // precautionary, so InitMessage/placement-new is unnecessary.
507
0
    mExtra.mMessage = aRHS.mExtra.mMessage = nullptr;
508
0
  }
509
0
510
#ifdef DEBUG
511
  mUnionState = aRHS.mUnionState;
512
  aRHS.mUnionState = HasNothing;
513
#endif // DEBUG
514
515
0
  // Note: It's important to do this last, since this affects the condition
516
0
  // checks above!
517
0
  mResult = aRHS.mResult;
518
0
  aRHS.mResult = NS_OK;
519
0
  return *this;
520
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::operator=(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>&&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::operator=(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>&&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::operator=(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>&&)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::operator=(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>&&)
521
522
template<typename CleanupPolicy>
523
bool
524
TErrorResult<CleanupPolicy>::operator==(const ErrorResult& aRight) const
525
0
{
526
0
  auto right = reinterpret_cast<const TErrorResult<CleanupPolicy>*>(&aRight);
527
0
528
0
  if (mResult != right->mResult) {
529
0
    return false;
530
0
  }
531
0
532
0
  if (IsJSException()) {
533
0
    // js exceptions are always non-equal
534
0
    return false;
535
0
  }
536
0
537
0
  if (IsErrorWithMessage()) {
538
0
    return *mExtra.mMessage == *right->mExtra.mMessage;
539
0
  }
540
0
541
0
  if (IsDOMException()) {
542
0
    return *mExtra.mDOMExceptionInfo == *right->mExtra.mDOMExceptionInfo;
543
0
  }
544
0
545
0
  return true;
546
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::operator==(mozilla::ErrorResult const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::operator==(mozilla::ErrorResult const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::operator==(mozilla::ErrorResult const&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::operator==(mozilla::ErrorResult const&) const
547
548
template<typename CleanupPolicy>
549
void
550
TErrorResult<CleanupPolicy>::CloneTo(TErrorResult& aRv) const
551
0
{
552
0
  AssertInOwningThread();
553
0
  aRv.AssertInOwningThread();
554
0
  aRv.ClearUnionData();
555
0
  aRv.mResult = mResult;
556
#ifdef DEBUG
557
  aRv.mMightHaveUnreportedJSException = mMightHaveUnreportedJSException;
558
#endif
559
560
0
  if (IsErrorWithMessage()) {
561
#ifdef DEBUG
562
    aRv.mUnionState = HasMessage;
563
#endif
564
    Message* message = aRv.InitMessage(new Message());
565
0
    message->mArgs = mExtra.mMessage->mArgs;
566
0
    message->mErrorNumber = mExtra.mMessage->mErrorNumber;
567
0
  } else if (IsDOMException()) {
568
#ifdef DEBUG
569
    aRv.mUnionState = HasDOMExceptionInfo;
570
#endif
571
    auto* exnInfo = new DOMExceptionInfo(mExtra.mDOMExceptionInfo->mRv,
572
0
                                         mExtra.mDOMExceptionInfo->mMessage);
573
0
    aRv.InitDOMExceptionInfo(exnInfo);
574
0
  } else if (IsJSException()) {
575
#ifdef DEBUG
576
    aRv.mUnionState = HasJSException;
577
#endif
578
    JSContext* cx = dom::danger::GetJSContext();
579
0
    JS::Rooted<JS::Value> exception(cx, mExtra.mJSException);
580
0
    aRv.ThrowJSException(cx, exception);
581
0
  }
582
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::CloneTo(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::CloneTo(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::CloneTo(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>&) const
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::CloneTo(mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>&) const
583
584
template<typename CleanupPolicy>
585
void
586
TErrorResult<CleanupPolicy>::SuppressException()
587
0
{
588
0
  AssertInOwningThread();
589
0
  WouldReportJSException();
590
0
  ClearUnionData();
591
0
  // We don't use AssignErrorCode, because we want to override existing error
592
0
  // states, which AssignErrorCode is not allowed to do.
593
0
  mResult = NS_OK;
594
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SuppressException()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SuppressException()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SuppressException()
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SuppressException()
595
596
template<typename CleanupPolicy>
597
void
598
TErrorResult<CleanupPolicy>::SetPendingException(JSContext* cx)
599
0
{
600
0
  AssertInOwningThread();
601
0
  if (IsUncatchableException()) {
602
0
    // Nuke any existing exception on cx, to make sure we're uncatchable.
603
0
    JS_ClearPendingException(cx);
604
0
    // Don't do any reporting.  Just return, to create an
605
0
    // uncatchable exception.
606
0
    mResult = NS_OK;
607
0
    return;
608
0
  }
609
0
  if (IsJSContextException()) {
610
0
    // Whatever we need to throw is on the JSContext already.
611
0
    MOZ_ASSERT(JS_IsExceptionPending(cx));
612
0
    mResult = NS_OK;
613
0
    return;
614
0
  }
615
0
  if (IsErrorWithMessage()) {
616
0
    SetPendingExceptionWithMessage(cx);
617
0
    return;
618
0
  }
619
0
  if (IsJSException()) {
620
0
    SetPendingJSException(cx);
621
0
    return;
622
0
  }
623
0
  if (IsDOMException()) {
624
0
    SetPendingDOMException(cx);
625
0
    return;
626
0
  }
627
0
  SetPendingGenericErrorException(cx);
628
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::SetPendingException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::SetPendingException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::SetPendingException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::SetPendingException(JSContext*)
629
630
template<typename CleanupPolicy>
631
void
632
TErrorResult<CleanupPolicy>::StealExceptionFromJSContext(JSContext* cx)
633
0
{
634
0
  AssertInOwningThread();
635
0
  MOZ_ASSERT(mMightHaveUnreportedJSException,
636
0
             "Why didn't you tell us you planned to throw a JS exception?");
637
0
638
0
  JS::Rooted<JS::Value> exn(cx);
639
0
  if (!JS_GetPendingException(cx, &exn)) {
640
0
    ThrowUncatchableException();
641
0
    return;
642
0
  }
643
0
644
0
  ThrowJSException(cx, exn);
645
0
  JS_ClearPendingException(cx);
646
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::StealExceptionFromJSContext(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::StealExceptionFromJSContext(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::StealExceptionFromJSContext(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::StealExceptionFromJSContext(JSContext*)
647
648
template<typename CleanupPolicy>
649
void
650
TErrorResult<CleanupPolicy>::NoteJSContextException(JSContext* aCx)
651
0
{
652
0
  AssertInOwningThread();
653
0
  if (JS_IsExceptionPending(aCx)) {
654
0
    mResult = NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT;
655
0
  } else {
656
0
    mResult = NS_ERROR_UNCATCHABLE_EXCEPTION;
657
0
  }
658
0
}
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustAssertCleanupPolicy>::NoteJSContextException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::AssertAndSuppressCleanupPolicy>::NoteJSContextException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::JustSuppressCleanupPolicy>::NoteJSContextException(JSContext*)
Unexecuted instantiation: mozilla::binding_danger::TErrorResult<mozilla::binding_danger::ThreadSafeJustSuppressCleanupPolicy>::NoteJSContextException(JSContext*)
659
660
template class TErrorResult<JustAssertCleanupPolicy>;
661
template class TErrorResult<AssertAndSuppressCleanupPolicy>;
662
template class TErrorResult<JustSuppressCleanupPolicy>;
663
template class TErrorResult<ThreadSafeJustSuppressCleanupPolicy>;
664
665
} // namespace binding_danger
666
667
namespace dom {
668
669
bool
670
DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
671
                const ConstantSpec* cs)
672
0
{
673
0
  JS::Rooted<JS::Value> value(cx);
674
0
  for (; cs->name; ++cs) {
675
0
    value = cs->value;
676
0
    bool ok =
677
0
      JS_DefineProperty(cx, obj, cs->name, value,
678
0
                        JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
679
0
    if (!ok) {
680
0
      return false;
681
0
    }
682
0
  }
683
0
  return true;
684
0
}
685
686
static inline bool
687
4
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) {
688
4
  return JS_DefineFunctions(cx, obj, spec);
689
4
}
690
static inline bool
691
1
Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) {
692
1
  return JS_DefineProperties(cx, obj, spec);
693
1
}
694
static inline bool
695
0
Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) {
696
0
  return DefineConstants(cx, obj, spec);
697
0
}
698
699
template<typename T>
700
bool
701
DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj,
702
               const Prefable<T>* props)
703
3
{
704
3
  MOZ_ASSERT(props);
705
3
  MOZ_ASSERT(props->specs);
706
6
  do {
707
6
    // Define if enabled
708
6
    if (props->isEnabled(cx, obj)) {
709
5
      if (!Define(cx, obj, props->specs)) {
710
0
        return false;
711
0
      }
712
6
    }
713
6
  } while ((++props)->specs);
714
3
  return true;
715
3
}
bool mozilla::dom::DefinePrefable<JSFunctionSpec const>(JSContext*, JS::Handle<JSObject*>, mozilla::dom::Prefable<JSFunctionSpec const> const*)
Line
Count
Source
703
2
{
704
2
  MOZ_ASSERT(props);
705
2
  MOZ_ASSERT(props->specs);
706
5
  do {
707
5
    // Define if enabled
708
5
    if (props->isEnabled(cx, obj)) {
709
4
      if (!Define(cx, obj, props->specs)) {
710
0
        return false;
711
0
      }
712
5
    }
713
5
  } while ((++props)->specs);
714
2
  return true;
715
2
}
bool mozilla::dom::DefinePrefable<JSPropertySpec const>(JSContext*, JS::Handle<JSObject*>, mozilla::dom::Prefable<JSPropertySpec const> const*)
Line
Count
Source
703
1
{
704
1
  MOZ_ASSERT(props);
705
1
  MOZ_ASSERT(props->specs);
706
1
  do {
707
1
    // Define if enabled
708
1
    if (props->isEnabled(cx, obj)) {
709
1
      if (!Define(cx, obj, props->specs)) {
710
0
        return false;
711
0
      }
712
1
    }
713
1
  } while ((++props)->specs);
714
1
  return true;
715
1
}
Unexecuted instantiation: bool mozilla::dom::DefinePrefable<mozilla::dom::ConstantSpec const>(JSContext*, JS::Handle<JSObject*>, mozilla::dom::Prefable<mozilla::dom::ConstantSpec const> const*)
716
717
bool
718
DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
719
                         const Prefable<const JSFunctionSpec>* props)
720
0
{
721
0
  return DefinePrefable(cx, obj, props);
722
0
}
723
724
bool
725
DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
726
                            const Prefable<const JSPropertySpec>* props)
727
0
{
728
0
  return DefinePrefable(cx, obj, props);
729
0
}
730
731
732
// We should use JSFunction objects for interface objects, but we need a custom
733
// hasInstance hook because we have new interface objects on prototype chains of
734
// old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
735
// reserved slots (e.g. for named constructors).  So we define a custom
736
// funToString ObjectOps member for interface objects.
737
JSString*
738
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
739
                        bool /* isToSource */)
740
0
{
741
0
  const js::Class* clasp = js::GetObjectClass(aObject);
742
0
  MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
743
0
744
0
  const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
745
0
    DOMIfaceAndProtoJSClass::FromJSClass(clasp);
746
0
  return JS_NewStringCopyZ(aCx, ifaceAndProtoJSClass->mToString);
747
0
}
748
749
bool
750
Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
751
0
{
752
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
753
0
  const JS::Value& v =
754
0
    js::GetFunctionNativeReserved(&args.callee(),
755
0
                                  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
756
0
  const JSNativeHolder* nativeHolder =
757
0
    static_cast<const JSNativeHolder*>(v.toPrivate());
758
0
  return (nativeHolder->mNative)(cx, argc, vp);
759
0
}
760
761
static JSObject*
762
CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
763
                  const JSNativeHolder* nativeHolder, unsigned ctorNargs)
764
0
{
765
0
  JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
766
0
                                                JSFUN_CONSTRUCTOR, name);
767
0
  if (!fun) {
768
0
    return nullptr;
769
0
  }
770
0
771
0
  JSObject* constructor = JS_GetFunctionObject(fun);
772
0
  js::SetFunctionNativeReserved(constructor,
773
0
                                CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
774
0
                                js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
775
0
  return constructor;
776
0
}
777
778
static bool
779
DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
780
                  JS::Handle<JSObject*> constructor)
781
2
{
782
2
  bool alreadyDefined;
783
2
  if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
784
0
    return false;
785
0
  }
786
2
787
2
  // This is Enumerable: False per spec.
788
2
  return alreadyDefined ||
789
2
         JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
790
2
}
791
792
static JSObject*
793
CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
794
                      JS::Handle<JSObject*> constructorProto,
795
                      const js::Class* constructorClass,
796
                      unsigned ctorNargs, const NamedConstructor* namedConstructors,
797
                      JS::Handle<JSObject*> proto,
798
                      const NativeProperties* properties,
799
                      const NativeProperties* chromeOnlyProperties,
800
                      const char* name, bool isChrome, bool defineOnGlobal)
801
2
{
802
2
  JS::Rooted<JSObject*> constructor(cx);
803
2
  MOZ_ASSERT(constructorProto);
804
2
  MOZ_ASSERT(constructorClass);
805
2
  constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
806
2
                                           constructorProto);
807
2
  if (!constructor) {
808
0
    return nullptr;
809
0
  }
810
2
811
2
  if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
812
2
                         JSPROP_READONLY)) {
813
0
    return nullptr;
814
0
  }
815
2
816
2
  // Might as well intern, since we're going to need an atomized
817
2
  // version of name anyway when we stick our constructor on the
818
2
  // global.
819
2
  JS::Rooted<JSString*> nameStr(cx, JS_AtomizeAndPinString(cx, name));
820
2
  if (!nameStr) {
821
0
    return nullptr;
822
0
  }
823
2
824
2
  if (!JS_DefineProperty(cx, constructor, "name", nameStr, JSPROP_READONLY)) {
825
0
    return nullptr;
826
0
  }
827
2
828
2
  if (DOMIfaceAndProtoJSClass::FromJSClass(constructorClass)->wantsInterfaceHasInstance) {
829
1
    JS::Rooted<jsid> hasInstanceId(cx,
830
1
      SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)));
831
1
    if (!JS_DefineFunctionById(cx, constructor, hasInstanceId,
832
1
                               InterfaceHasInstance, 1,
833
1
                               // Flags match those of Function[Symbol.hasInstance]
834
1
                               JSPROP_READONLY | JSPROP_PERMANENT)) {
835
0
      return nullptr;
836
0
    }
837
1
838
1
    if (isChrome && !JS_DefineFunction(cx, constructor, "isInstance",
839
1
                                       InterfaceIsInstance, 1,
840
1
                                       // Don't bother making it enumerable
841
1
                                       0)) {
842
0
      return nullptr;
843
0
    }
844
2
  }
845
2
846
2
  if (properties) {
847
1
    if (properties->HasStaticMethods() &&
848
1
        !DefinePrefable(cx, constructor, properties->StaticMethods())) {
849
0
      return nullptr;
850
0
    }
851
1
852
1
    if (properties->HasStaticAttributes() &&
853
1
        !DefinePrefable(cx, constructor, properties->StaticAttributes())) {
854
0
      return nullptr;
855
0
    }
856
1
857
1
    if (properties->HasConstants() &&
858
1
        !DefinePrefable(cx, constructor, properties->Constants())) {
859
0
      return nullptr;
860
0
    }
861
2
  }
862
2
863
2
  if (chromeOnlyProperties && isChrome) {
864
1
    if (chromeOnlyProperties->HasStaticMethods() &&
865
1
        !DefinePrefable(cx, constructor,
866
1
                        chromeOnlyProperties->StaticMethods())) {
867
0
      return nullptr;
868
0
    }
869
1
870
1
    if (chromeOnlyProperties->HasStaticAttributes() &&
871
1
        !DefinePrefable(cx, constructor,
872
0
                        chromeOnlyProperties->StaticAttributes())) {
873
0
      return nullptr;
874
0
    }
875
1
876
1
    if (chromeOnlyProperties->HasConstants() &&
877
1
        !DefinePrefable(cx, constructor, chromeOnlyProperties->Constants())) {
878
0
      return nullptr;
879
0
    }
880
2
  }
881
2
882
2
  if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) {
883
0
    return nullptr;
884
0
  }
885
2
886
2
  if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
887
0
    return nullptr;
888
0
  }
889
2
890
2
  if (namedConstructors) {
891
0
    int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE;
892
0
    while (namedConstructors->mName) {
893
0
      JS::Rooted<JSObject*> namedConstructor(cx,
894
0
        CreateConstructor(cx, global, namedConstructors->mName,
895
0
                          &namedConstructors->mHolder,
896
0
                          namedConstructors->mNargs));
897
0
      if (!namedConstructor ||
898
0
          !JS_DefineProperty(cx, namedConstructor, "prototype",
899
0
                             proto,
900
0
                             JSPROP_PERMANENT | JSPROP_READONLY) ||
901
0
          (defineOnGlobal &&
902
0
           !DefineConstructor(cx, global, namedConstructors->mName,
903
0
                              namedConstructor))) {
904
0
        return nullptr;
905
0
      }
906
0
      js::SetReservedSlot(constructor, namedConstructorSlot++,
907
0
                          JS::ObjectValue(*namedConstructor));
908
0
      ++namedConstructors;
909
0
    }
910
0
  }
911
2
912
2
  return constructor;
913
2
}
914
915
static JSObject*
916
CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
917
                               JS::Handle<JSObject*> parentProto,
918
                               const js::Class* protoClass,
919
                               const NativeProperties* properties,
920
                               const NativeProperties* chromeOnlyProperties,
921
                               const char* const* unscopableNames,
922
                               const char* toStringTag,
923
                               bool isGlobal)
924
1
{
925
1
  JS::Rooted<JSObject*> ourProto(cx,
926
1
    JS_NewObjectWithUniqueType(cx, Jsvalify(protoClass), parentProto));
927
1
  if (!ourProto ||
928
1
      // We don't try to define properties on the global's prototype; those
929
1
      // properties go on the global itself.
930
1
      (!isGlobal &&
931
1
       !DefineProperties(cx, ourProto, properties, chromeOnlyProperties))) {
932
0
    return nullptr;
933
0
  }
934
1
935
1
  if (unscopableNames) {
936
0
    JS::Rooted<JSObject*> unscopableObj(cx,
937
0
      JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
938
0
    if (!unscopableObj) {
939
0
      return nullptr;
940
0
    }
941
0
942
0
    for (; *unscopableNames; ++unscopableNames) {
943
0
      if (!JS_DefineProperty(cx, unscopableObj, *unscopableNames,
944
0
                             JS::TrueHandleValue, JSPROP_ENUMERATE)) {
945
0
        return nullptr;
946
0
      }
947
0
    }
948
0
949
0
    JS::Rooted<jsid> unscopableId(cx,
950
0
      SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::unscopables)));
951
0
    // Readonly and non-enumerable to match Array.prototype.
952
0
    if (!JS_DefinePropertyById(cx, ourProto, unscopableId, unscopableObj,
953
0
                               JSPROP_READONLY)) {
954
0
      return nullptr;
955
0
    }
956
1
  }
957
1
958
1
  if (toStringTag) {
959
0
    JS::Rooted<JSString*> toStringTagStr(cx,
960
0
                                         JS_NewStringCopyZ(cx, toStringTag));
961
0
    if (!toStringTagStr) {
962
0
      return nullptr;
963
0
    }
964
0
965
0
    JS::Rooted<jsid> toStringTagId(cx,
966
0
      SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::toStringTag)));
967
0
    if (!JS_DefinePropertyById(cx, ourProto, toStringTagId, toStringTagStr,
968
0
                               JSPROP_READONLY)) {
969
0
      return nullptr;
970
0
    }
971
1
  }
972
1
973
1
  return ourProto;
974
1
}
975
976
bool
977
DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
978
                 const NativeProperties* properties,
979
                 const NativeProperties* chromeOnlyProperties)
980
1
{
981
1
  if (properties) {
982
0
    if (properties->HasMethods() &&
983
0
        !DefinePrefable(cx, obj, properties->Methods())) {
984
0
      return false;
985
0
    }
986
0
987
0
    if (properties->HasAttributes() &&
988
0
        !DefinePrefable(cx, obj, properties->Attributes())) {
989
0
      return false;
990
0
    }
991
0
992
0
    if (properties->HasConstants() &&
993
0
        !DefinePrefable(cx, obj, properties->Constants())) {
994
0
      return false;
995
0
    }
996
1
  }
997
1
998
1
  if (chromeOnlyProperties) {
999
0
    if (chromeOnlyProperties->HasMethods() &&
1000
0
        !DefinePrefable(cx, obj, chromeOnlyProperties->Methods())) {
1001
0
      return false;
1002
0
    }
1003
0
1004
0
    if (chromeOnlyProperties->HasAttributes() &&
1005
0
        !DefinePrefable(cx, obj, chromeOnlyProperties->Attributes())) {
1006
0
      return false;
1007
0
    }
1008
0
1009
0
    if (chromeOnlyProperties->HasConstants() &&
1010
0
        !DefinePrefable(cx, obj, chromeOnlyProperties->Constants())) {
1011
0
      return false;
1012
0
    }
1013
1
  }
1014
1
1015
1
  return true;
1016
1
}
1017
1018
void
1019
CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
1020
                       JS::Handle<JSObject*> protoProto,
1021
                       const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
1022
                       const char* toStringTag,
1023
                       JS::Handle<JSObject*> constructorProto,
1024
                       const js::Class* constructorClass,
1025
                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
1026
                       JS::Heap<JSObject*>* constructorCache,
1027
                       const NativeProperties* properties,
1028
                       const NativeProperties* chromeOnlyProperties,
1029
                       const char* name, bool defineOnGlobal,
1030
                       const char* const* unscopableNames,
1031
                       bool isGlobal)
1032
2
{
1033
2
  MOZ_ASSERT(protoClass || constructorClass,
1034
2
             "Need at least one class!");
1035
2
  MOZ_ASSERT(!((properties &&
1036
2
                (properties->HasMethods() || properties->HasAttributes())) ||
1037
2
               (chromeOnlyProperties &&
1038
2
                (chromeOnlyProperties->HasMethods() ||
1039
2
                 chromeOnlyProperties->HasAttributes()))) || protoClass,
1040
2
             "Methods or properties but no protoClass!");
1041
2
  MOZ_ASSERT(!((properties &&
1042
2
                (properties->HasStaticMethods() ||
1043
2
                 properties->HasStaticAttributes())) ||
1044
2
               (chromeOnlyProperties &&
1045
2
                (chromeOnlyProperties->HasStaticMethods() ||
1046
2
                 chromeOnlyProperties->HasStaticAttributes()))) ||
1047
2
             constructorClass,
1048
2
             "Static methods but no constructorClass!");
1049
2
  MOZ_ASSERT(bool(name) == bool(constructorClass),
1050
2
             "Must have name precisely when we have an interface object");
1051
2
  MOZ_ASSERT(!protoClass == !protoCache,
1052
2
             "If, and only if, there is an interface prototype object we need "
1053
2
             "to cache it");
1054
2
  MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
1055
2
             "If, and only if, there is an interface object we need to cache "
1056
2
             "it");
1057
2
  MOZ_ASSERT(constructorProto || !constructorClass,
1058
2
             "Must have a constructor proto if we plan to create a constructor "
1059
2
             "object");
1060
2
  MOZ_ASSERT(protoClass || !toStringTag,
1061
2
             "Must have a prototype object if we have a @@toStringTag");
1062
2
1063
2
  bool isChrome = nsContentUtils::ThreadsafeIsSystemCaller(cx);
1064
2
1065
2
  JS::Rooted<JSObject*> proto(cx);
1066
2
  if (protoClass) {
1067
1
    proto =
1068
1
      CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
1069
1
                                     properties,
1070
1
                                     isChrome ? chromeOnlyProperties : nullptr,
1071
1
                                     unscopableNames, toStringTag, isGlobal);
1072
1
    if (!proto) {
1073
0
      return;
1074
0
    }
1075
1
1076
1
    *protoCache = proto;
1077
1
  }
1078
1
  else {
1079
1
    MOZ_ASSERT(!proto);
1080
1
  }
1081
2
1082
2
  JSObject* interface;
1083
2
  if (constructorClass) {
1084
2
    interface = CreateInterfaceObject(cx, global, constructorProto,
1085
2
                                      constructorClass, ctorNargs,
1086
2
                                      namedConstructors, proto, properties,
1087
2
                                      chromeOnlyProperties, name,
1088
2
                                      isChrome,
1089
2
                                      defineOnGlobal);
1090
2
    if (!interface) {
1091
0
      if (protoCache) {
1092
0
        // If we fail we need to make sure to clear the value of protoCache we
1093
0
        // set above.
1094
0
        *protoCache = nullptr;
1095
0
      }
1096
0
      return;
1097
0
    }
1098
2
    *constructorCache = interface;
1099
2
  }
1100
2
}
1101
1102
// Only set aAllowNativeWrapper to false if you really know you need it; if in
1103
// doubt use true. Setting it to false disables security wrappers.
1104
static bool
1105
NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
1106
                                         JS::Handle<JSObject*> aScope,
1107
                                         JS::MutableHandle<JS::Value> aRetval,
1108
                                         xpcObjectHelper& aHelper,
1109
                                         const nsIID* aIID,
1110
                                         bool aAllowNativeWrapper)
1111
0
{
1112
0
  js::AssertSameCompartment(aCx, aScope);
1113
0
  nsresult rv;
1114
0
  // Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
1115
0
  // on all threads.
1116
0
  nsWrapperCache *cache = aHelper.GetWrapperCache();
1117
0
1118
0
  if (cache) {
1119
0
      JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
1120
0
      if (!obj) {
1121
0
        obj = cache->WrapObject(aCx, nullptr);
1122
0
        if (!obj) {
1123
0
          return Throw(aCx, NS_ERROR_UNEXPECTED);
1124
0
        }
1125
0
      }
1126
0
1127
0
      if (aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) {
1128
0
        return false;
1129
0
      }
1130
0
1131
0
      aRetval.setObject(*obj);
1132
0
      return true;
1133
0
  }
1134
0
1135
0
  MOZ_ASSERT(NS_IsMainThread());
1136
0
1137
0
  if (!XPCConvert::NativeInterface2JSObject(aRetval, aHelper, aIID,
1138
0
                                            aAllowNativeWrapper, &rv)) {
1139
0
    // I can't tell if NativeInterface2JSObject throws JS exceptions
1140
0
    // or not.  This is a sloppy stab at the right semantics; the
1141
0
    // method really ought to be fixed to behave consistently.
1142
0
    if (!JS_IsExceptionPending(aCx)) {
1143
0
      Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
1144
0
    }
1145
0
    return false;
1146
0
  }
1147
0
  return true;
1148
0
}
1149
1150
bool
1151
TryPreserveWrapper(JS::Handle<JSObject*> obj)
1152
0
{
1153
0
  MOZ_ASSERT(IsDOMObject(obj));
1154
0
1155
0
  // nsISupports objects are special cased because DOM proxies are nsISupports
1156
0
  // and have addProperty hooks that do more than wrapper preservation (so we
1157
0
  // don't want to call them).
1158
0
  if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) {
1159
0
    nsWrapperCache* cache = nullptr;
1160
0
    CallQueryInterface(native, &cache);
1161
0
    if (cache) {
1162
0
      cache->PreserveWrapper(native);
1163
0
    }
1164
0
    return true;
1165
0
  }
1166
0
1167
0
  // The addProperty hook for WebIDL classes does wrapper preservation, and
1168
0
  // nothing else, so call it, if present.
1169
0
  const DOMJSClass* domClass = GetDOMClass(obj);
1170
0
  const JSClass* clasp = domClass->ToJSClass();
1171
0
  JSAddPropertyOp addProperty = clasp->getAddProperty();
1172
0
1173
0
  // We expect all proxies to be nsISupports.
1174
0
  MOZ_RELEASE_ASSERT(!js::Valueify(clasp)->isProxy(), "Should not call addProperty for proxies.");
1175
0
1176
0
  // The class should have an addProperty hook iff it is a CC participant.
1177
0
  MOZ_RELEASE_ASSERT(bool(domClass->mParticipant) == bool(addProperty));
1178
0
1179
0
  if (!addProperty) {
1180
0
    return true;
1181
0
  }
1182
0
1183
0
  JS::Rooted<jsid> dummyId(RootingCx());
1184
0
  JS::Rooted<JS::Value> dummyValue(RootingCx());
1185
0
  return addProperty(nullptr, obj, dummyId, dummyValue);
1186
0
}
1187
1188
// Can only be called with a DOM JSClass.
1189
bool
1190
InstanceClassHasProtoAtDepth(const js::Class* clasp,
1191
                             uint32_t protoID, uint32_t depth)
1192
0
{
1193
0
  const DOMJSClass* domClass = DOMJSClass::FromJSClass(clasp);
1194
0
  return static_cast<uint32_t>(domClass->mInterfaceChain[depth]) == protoID;
1195
0
}
1196
1197
// Only set allowNativeWrapper to false if you really know you need it; if in
1198
// doubt use true. Setting it to false disables security wrappers.
1199
bool
1200
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
1201
                   xpcObjectHelper& helper, const nsIID* iid,
1202
                   bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
1203
0
{
1204
0
  return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
1205
0
                                                  allowNativeWrapper);
1206
0
}
1207
1208
bool
1209
VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
1210
               JS::MutableHandle<JS::Value> aRetval)
1211
0
{
1212
0
  nsresult rv;
1213
0
  if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
1214
0
    // Does it throw?  Who knows
1215
0
    if (!JS_IsExceptionPending(aCx)) {
1216
0
      Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
1217
0
    }
1218
0
    return false;
1219
0
  }
1220
0
1221
0
  return true;
1222
0
}
1223
1224
static int
1225
CompareIdsAtIndices(const void* aElement1, const void* aElement2, void* aClosure)
1226
100
{
1227
100
  const uint16_t index1 = *static_cast<const uint16_t*>(aElement1);
1228
100
  const uint16_t index2 = *static_cast<const uint16_t*>(aElement2);
1229
100
  const PropertyInfo* infos = static_cast<PropertyInfo*>(aClosure);
1230
100
1231
100
  MOZ_ASSERT(JSID_BITS(infos[index1].Id()) != JSID_BITS(infos[index2].Id()));
1232
100
1233
100
  return JSID_BITS(infos[index1].Id()) < JSID_BITS(infos[index2].Id()) ? -1 : 1;
1234
100
}
1235
1236
template <typename SpecT>
1237
static bool
1238
InitIdsInternal(JSContext* cx, const Prefable<SpecT>* pref, PropertyInfo* infos,
1239
                PropertyType type)
1240
3
{
1241
3
  MOZ_ASSERT(pref);
1242
3
  MOZ_ASSERT(pref->specs);
1243
3
1244
3
  // Index of the Prefable that contains the id for the current PropertyInfo.
1245
3
  uint32_t prefIndex = 0;
1246
3
1247
6
  do {
1248
6
    // We ignore whether the set of ids is enabled and just intern all the IDs,
1249
6
    // because this is only done once per application runtime.
1250
6
    const SpecT* spec = pref->specs;
1251
6
    // Index of the property/function/constant spec for our current PropertyInfo
1252
6
    // in the "specs" array of the relevant Prefable.
1253
6
    uint32_t specIndex = 0;
1254
28
    do {
1255
28
      jsid id;
1256
28
      if (!JS::PropertySpecNameToPermanentId(cx, spec->name, &id)) {
1257
0
        return false;
1258
0
      }
1259
28
      infos->SetId(id);
1260
28
      infos->type = type;
1261
28
      infos->prefIndex = prefIndex;
1262
28
      infos->specIndex = specIndex++;
1263
28
      ++infos;
1264
28
    } while ((++spec)->name);
1265
6
    ++prefIndex;
1266
6
  } while ((++pref)->specs);
1267
3
1268
3
  return true;
1269
3
}
Unified_cpp_dom_bindings0.cpp:bool mozilla::dom::InitIdsInternal<JSFunctionSpec const>(JSContext*, mozilla::dom::Prefable<JSFunctionSpec const> const*, mozilla::dom::PropertyInfo*, mozilla::dom::PropertyType)
Line
Count
Source
1240
2
{
1241
2
  MOZ_ASSERT(pref);
1242
2
  MOZ_ASSERT(pref->specs);
1243
2
1244
2
  // Index of the Prefable that contains the id for the current PropertyInfo.
1245
2
  uint32_t prefIndex = 0;
1246
2
1247
5
  do {
1248
5
    // We ignore whether the set of ids is enabled and just intern all the IDs,
1249
5
    // because this is only done once per application runtime.
1250
5
    const SpecT* spec = pref->specs;
1251
5
    // Index of the property/function/constant spec for our current PropertyInfo
1252
5
    // in the "specs" array of the relevant Prefable.
1253
5
    uint32_t specIndex = 0;
1254
27
    do {
1255
27
      jsid id;
1256
27
      if (!JS::PropertySpecNameToPermanentId(cx, spec->name, &id)) {
1257
0
        return false;
1258
0
      }
1259
27
      infos->SetId(id);
1260
27
      infos->type = type;
1261
27
      infos->prefIndex = prefIndex;
1262
27
      infos->specIndex = specIndex++;
1263
27
      ++infos;
1264
27
    } while ((++spec)->name);
1265
5
    ++prefIndex;
1266
5
  } while ((++pref)->specs);
1267
2
1268
2
  return true;
1269
2
}
Unified_cpp_dom_bindings0.cpp:bool mozilla::dom::InitIdsInternal<JSPropertySpec const>(JSContext*, mozilla::dom::Prefable<JSPropertySpec const> const*, mozilla::dom::PropertyInfo*, mozilla::dom::PropertyType)
Line
Count
Source
1240
1
{
1241
1
  MOZ_ASSERT(pref);
1242
1
  MOZ_ASSERT(pref->specs);
1243
1
1244
1
  // Index of the Prefable that contains the id for the current PropertyInfo.
1245
1
  uint32_t prefIndex = 0;
1246
1
1247
1
  do {
1248
1
    // We ignore whether the set of ids is enabled and just intern all the IDs,
1249
1
    // because this is only done once per application runtime.
1250
1
    const SpecT* spec = pref->specs;
1251
1
    // Index of the property/function/constant spec for our current PropertyInfo
1252
1
    // in the "specs" array of the relevant Prefable.
1253
1
    uint32_t specIndex = 0;
1254
1
    do {
1255
1
      jsid id;
1256
1
      if (!JS::PropertySpecNameToPermanentId(cx, spec->name, &id)) {
1257
0
        return false;
1258
0
      }
1259
1
      infos->SetId(id);
1260
1
      infos->type = type;
1261
1
      infos->prefIndex = prefIndex;
1262
1
      infos->specIndex = specIndex++;
1263
1
      ++infos;
1264
1
    } while ((++spec)->name);
1265
1
    ++prefIndex;
1266
1
  } while ((++pref)->specs);
1267
1
1268
1
  return true;
1269
1
}
Unexecuted instantiation: Unified_cpp_dom_bindings0.cpp:bool mozilla::dom::InitIdsInternal<mozilla::dom::ConstantSpec const>(JSContext*, mozilla::dom::Prefable<mozilla::dom::ConstantSpec const> const*, mozilla::dom::PropertyInfo*, mozilla::dom::PropertyType)
1270
1271
14
#define INIT_IDS_IF_DEFINED(TypeName) {                                       \
1272
14
  if (nativeProperties->Has##TypeName##s() &&                                 \
1273
14
      !InitIdsInternal(cx,                                                    \
1274
3
                       nativeProperties->TypeName##s(),                       \
1275
3
                       nativeProperties->TypeName##PropertyInfos(),           \
1276
3
                       e##TypeName)) {                                        \
1277
0
    return false;                                                             \
1278
0
  }                                                                           \
1279
14
}
1280
1281
bool
1282
InitIds(JSContext* cx, const NativeProperties* nativeProperties)
1283
2
{
1284
2
  INIT_IDS_IF_DEFINED(StaticMethod);
1285
2
  INIT_IDS_IF_DEFINED(StaticAttribute);
1286
2
  INIT_IDS_IF_DEFINED(Method);
1287
2
  INIT_IDS_IF_DEFINED(Attribute);
1288
2
  INIT_IDS_IF_DEFINED(UnforgeableMethod);
1289
2
  INIT_IDS_IF_DEFINED(UnforgeableAttribute);
1290
2
  INIT_IDS_IF_DEFINED(Constant);
1291
2
1292
2
  // Initialize and sort the index array.
1293
2
  uint16_t* indices = nativeProperties->sortedPropertyIndices;
1294
30
  for (unsigned int i = 0; i < nativeProperties->propertyInfoCount; ++i) {
1295
28
    indices[i] = i;
1296
28
  }
1297
2
  // CompareIdsAtIndices() doesn't actually modify the PropertyInfo array, so
1298
2
  // the const_cast here is OK in spite of the signature of NS_QuickSort().
1299
2
  NS_QuickSort(indices, nativeProperties->propertyInfoCount, sizeof(uint16_t),
1300
2
               CompareIdsAtIndices,
1301
2
               const_cast<PropertyInfo*>(nativeProperties->PropertyInfos()));
1302
2
1303
2
  return true;
1304
2
}
1305
1306
#undef INIT_IDS_IF_DEFINED
1307
1308
bool
1309
QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
1310
0
{
1311
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
1312
0
  if (!args.thisv().isObject()) {
1313
0
    JS_ReportErrorASCII(cx, "QueryInterface called on incompatible non-object");
1314
0
    return false;
1315
0
  }
1316
0
1317
0
  // Get the object. It might be a security wrapper, in which case we do a checked
1318
0
  // unwrap.
1319
0
  JS::Rooted<JSObject*> origObj(cx, &args.thisv().toObject());
1320
0
  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(origObj,
1321
0
                                                  /* stopAtWindowProxy = */ false));
1322
0
  if (!obj) {
1323
0
      JS_ReportErrorASCII(cx, "Permission denied to access object");
1324
0
      return false;
1325
0
  }
1326
0
1327
0
  nsCOMPtr<nsISupports> native = UnwrapDOMObjectToISupports(obj);
1328
0
  if (!native) {
1329
0
    return Throw(cx, NS_ERROR_FAILURE);
1330
0
  }
1331
0
1332
0
  if (argc < 1) {
1333
0
    return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
1334
0
  }
1335
0
1336
0
  if (!args[0].isObject()) {
1337
0
    return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
1338
0
  }
1339
0
1340
0
  nsCOMPtr<nsIJSID> iid;
1341
0
  obj = &args[0].toObject();
1342
0
  if (NS_FAILED(UnwrapArg<nsIJSID>(cx, obj, getter_AddRefs(iid)))) {
1343
0
    return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
1344
0
  }
1345
0
  MOZ_ASSERT(iid);
1346
0
1347
0
  if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) {
1348
0
    nsresult rv;
1349
0
    nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
1350
0
    if (NS_FAILED(rv)) {
1351
0
      return Throw(cx, rv);
1352
0
    }
1353
0
1354
0
    return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval());
1355
0
  }
1356
0
1357
0
  nsCOMPtr<nsISupports> unused;
1358
0
  nsresult rv = native->QueryInterface(*iid->GetID(), getter_AddRefs(unused));
1359
0
  if (NS_FAILED(rv)) {
1360
0
    return Throw(cx, rv);
1361
0
  }
1362
0
1363
0
  args.rval().set(args.thisv());
1364
0
  return true;
1365
0
}
1366
1367
void
1368
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
1369
                 nsWrapperCache* aCache, nsIJSID* aIID,
1370
                 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
1371
0
{
1372
0
  const nsID* iid = aIID->GetID();
1373
0
1374
0
  RefPtr<nsISupports> result;
1375
0
  aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
1376
0
  if (aError.Failed()) {
1377
0
    return;
1378
0
  }
1379
0
1380
0
  if (!WrapObject(aCx, result, iid, aRetval)) {
1381
0
    aError.Throw(NS_ERROR_FAILURE);
1382
0
  }
1383
0
}
1384
1385
bool
1386
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
1387
0
{
1388
0
  return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
1389
0
}
1390
1391
bool
1392
ThrowConstructorWithoutNew(JSContext* cx, const char* name)
1393
0
{
1394
0
  return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name);
1395
0
}
1396
1397
inline const NativePropertyHooks*
1398
GetNativePropertyHooksFromConstructorFunction(JS::Handle<JSObject*> obj)
1399
0
{
1400
0
  MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
1401
0
  const JS::Value& v =
1402
0
    js::GetFunctionNativeReserved(obj,
1403
0
                                  CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
1404
0
  const JSNativeHolder* nativeHolder =
1405
0
    static_cast<const JSNativeHolder*>(v.toPrivate());
1406
0
  return nativeHolder->mPropertyHooks;
1407
0
}
1408
1409
inline const NativePropertyHooks*
1410
GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
1411
                       DOMObjectType& type)
1412
0
{
1413
0
  const js::Class* clasp = js::GetObjectClass(obj);
1414
0
1415
0
  const DOMJSClass* domClass = GetDOMClass(clasp);
1416
0
  if (domClass) {
1417
0
    bool isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
1418
0
    type = isGlobal ? eGlobalInstance : eInstance;
1419
0
    return domClass->mNativeHooks;
1420
0
  }
1421
0
1422
0
  if (JS_ObjectIsFunction(cx, obj)) {
1423
0
    type = eInterface;
1424
0
    return GetNativePropertyHooksFromConstructorFunction(obj);
1425
0
  }
1426
0
1427
0
  MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
1428
0
  const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
1429
0
    DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
1430
0
  type = ifaceAndProtoJSClass->mType;
1431
0
  return ifaceAndProtoJSClass->mNativeHooks;
1432
0
}
1433
1434
static JSObject*
1435
XrayCreateFunction(JSContext* cx, JS::Handle<JSObject*> wrapper,
1436
                   JSNativeWrapper native, unsigned nargs, JS::Handle<jsid> id)
1437
0
{
1438
0
  JSFunction* fun;
1439
0
  if (JSID_IS_STRING(id)) {
1440
0
    fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0, id);
1441
0
  } else {
1442
0
    // Can't pass this id (probably a symbol) to NewFunctionByIdWithReserved;
1443
0
    // just use an empty name for lack of anything better.
1444
0
    fun = js::NewFunctionWithReserved(cx, native.op, nargs, 0, nullptr);
1445
0
  }
1446
0
1447
0
  if (!fun) {
1448
0
    return nullptr;
1449
0
  }
1450
0
1451
0
  SET_JITINFO(fun, native.info);
1452
0
  JSObject* obj = JS_GetFunctionObject(fun);
1453
0
  js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT,
1454
0
                                JS::ObjectValue(*wrapper));
1455
#ifdef DEBUG
1456
  js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF,
1457
                                JS::ObjectValue(*obj));
1458
#endif
1459
  return obj;
1460
0
}
1461
1462
struct IdToIndexComparator
1463
{
1464
  // The id we're searching for.
1465
  const jsid& mId;
1466
  // The list of ids we're searching in.
1467
  const PropertyInfo* mInfos;
1468
1469
  explicit IdToIndexComparator(const jsid& aId, const PropertyInfo* aInfos) :
1470
0
    mId(aId), mInfos(aInfos) {}
1471
0
  int operator()(const uint16_t aIndex) const {
1472
0
    if (JSID_BITS(mId) == JSID_BITS(mInfos[aIndex].Id())) {
1473
0
      return 0;
1474
0
    }
1475
0
    return JSID_BITS(mId) < JSID_BITS(mInfos[aIndex].Id()) ? -1 : 1;
1476
0
  }
1477
};
1478
1479
static const PropertyInfo*
1480
XrayFindOwnPropertyInfo(JSContext* cx, JS::Handle<jsid> id,
1481
                        const NativeProperties* nativeProperties)
1482
0
{
1483
0
  if (MOZ_UNLIKELY(nativeProperties->iteratorAliasMethodIndex >= 0) &&
1484
0
      id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::iterator))) {
1485
0
    return nativeProperties->MethodPropertyInfos() +
1486
0
           nativeProperties->iteratorAliasMethodIndex;
1487
0
  }
1488
0
1489
0
  size_t idx;
1490
0
  const uint16_t* sortedPropertyIndices = nativeProperties->sortedPropertyIndices;
1491
0
  const PropertyInfo* propertyInfos = nativeProperties->PropertyInfos();
1492
0
1493
0
  if (BinarySearchIf(sortedPropertyIndices, 0,
1494
0
                     nativeProperties->propertyInfoCount,
1495
0
                     IdToIndexComparator(id, propertyInfos), &idx)) {
1496
0
    return propertyInfos + sortedPropertyIndices[idx];
1497
0
  }
1498
0
1499
0
  return nullptr;
1500
0
}
1501
1502
static bool
1503
XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
1504
                     JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1505
                     const Prefable<const JSPropertySpec>& pref,
1506
                     const JSPropertySpec& attrSpec,
1507
                     JS::MutableHandle<JS::PropertyDescriptor> desc,
1508
                     bool& cacheOnHolder)
1509
0
{
1510
0
  if (!pref.isEnabled(cx, obj)) {
1511
0
    return true;
1512
0
  }
1513
0
1514
0
  cacheOnHolder = true;
1515
0
1516
0
  // Because of centralization, we need to make sure we fault in the JitInfos as
1517
0
  // well. At present, until the JSAPI changes, the easiest way to do this is
1518
0
  // wrap them up as functions ourselves.
1519
0
  desc.setAttributes(attrSpec.flags);
1520
0
  // They all have getters, so we can just make it.
1521
0
  JS::Rooted<JSObject*> funobj(cx,
1522
0
    XrayCreateFunction(cx, wrapper, attrSpec.accessors.getter.native, 0, id));
1523
0
  if (!funobj)
1524
0
    return false;
1525
0
  desc.setGetterObject(funobj);
1526
0
  desc.attributesRef() |= JSPROP_GETTER;
1527
0
  if (attrSpec.accessors.setter.native.op) {
1528
0
    // We have a setter! Make it.
1529
0
    funobj =
1530
0
      XrayCreateFunction(cx, wrapper, attrSpec.accessors.setter.native, 1, id);
1531
0
    if (!funobj)
1532
0
      return false;
1533
0
    desc.setSetterObject(funobj);
1534
0
    desc.attributesRef() |= JSPROP_SETTER;
1535
0
  } else {
1536
0
    desc.setSetter(nullptr);
1537
0
  }
1538
0
  desc.object().set(wrapper);
1539
0
  desc.value().setUndefined();
1540
0
1541
0
  return true;
1542
0
}
1543
1544
static bool
1545
XrayResolveMethod(JSContext* cx, JS::Handle<JSObject*> wrapper,
1546
                  JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1547
                  const Prefable<const JSFunctionSpec>& pref,
1548
                  const JSFunctionSpec& methodSpec,
1549
                  JS::MutableHandle<JS::PropertyDescriptor> desc,
1550
                  bool& cacheOnHolder)
1551
0
{
1552
0
  if (!pref.isEnabled(cx, obj)) {
1553
0
    return true;
1554
0
  }
1555
0
1556
0
  cacheOnHolder = true;
1557
0
1558
0
  JSObject *funobj;
1559
0
  if (methodSpec.selfHostedName) {
1560
0
    JSFunction* fun =
1561
0
      JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
1562
0
                                methodSpec.nargs);
1563
0
    if (!fun) {
1564
0
      return false;
1565
0
    }
1566
0
    MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
1567
0
    MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
1568
0
    funobj = JS_GetFunctionObject(fun);
1569
0
  } else {
1570
0
    funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
1571
0
                                methodSpec.nargs, id);
1572
0
    if (!funobj) {
1573
0
      return false;
1574
0
    }
1575
0
  }
1576
0
  desc.value().setObject(*funobj);
1577
0
  desc.setAttributes(methodSpec.flags);
1578
0
  desc.object().set(wrapper);
1579
0
  desc.setSetter(nullptr);
1580
0
  desc.setGetter(nullptr);
1581
0
1582
0
  return true;
1583
0
}
1584
1585
static bool
1586
XrayResolveConstant(JSContext* cx, JS::Handle<JSObject*> wrapper,
1587
                    JS::Handle<JSObject*> obj, JS::Handle<jsid>,
1588
                    const Prefable<const ConstantSpec>& pref,
1589
                    const ConstantSpec& constantSpec,
1590
                    JS::MutableHandle<JS::PropertyDescriptor> desc,
1591
                    bool& cacheOnHolder)
1592
0
{
1593
0
  if (!pref.isEnabled(cx, obj)) {
1594
0
    return true;
1595
0
  }
1596
0
1597
0
  cacheOnHolder = true;
1598
0
1599
0
  desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
1600
0
  desc.object().set(wrapper);
1601
0
  desc.value().set(constantSpec.value);
1602
0
1603
0
  return true;
1604
0
}
1605
1606
#define RESOLVE_CASE(PropType, SpecType, Resolver)                            \
1607
0
  case e##PropType: {                                                         \
1608
0
    MOZ_ASSERT(nativeProperties->Has##PropType##s());                         \
1609
0
    const Prefable<const SpecType>& pref =                                    \
1610
0
      nativeProperties->PropType##s()[propertyInfo.prefIndex];                \
1611
0
    return Resolver(cx, wrapper, obj, id, pref,                               \
1612
0
                    pref.specs[propertyInfo.specIndex], desc, cacheOnHolder); \
1613
0
  }
1614
1615
static bool
1616
XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
1617
                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1618
                    JS::MutableHandle<JS::PropertyDescriptor> desc,
1619
                    bool& cacheOnHolder, DOMObjectType type,
1620
                    const NativeProperties* nativeProperties,
1621
                    const PropertyInfo& propertyInfo)
1622
0
{
1623
0
  MOZ_ASSERT(type != eGlobalInterfacePrototype);
1624
0
1625
0
  // Make sure we resolve for matched object type.
1626
0
  switch (propertyInfo.type) {
1627
0
  case eStaticMethod:
1628
0
  case eStaticAttribute:
1629
0
    if (type != eInterface) {
1630
0
      return true;
1631
0
    }
1632
0
    break;
1633
0
  case eMethod:
1634
0
  case eAttribute:
1635
0
    if (type != eGlobalInstance && type != eInterfacePrototype) {
1636
0
      return true;
1637
0
    }
1638
0
    break;
1639
0
  case eUnforgeableMethod:
1640
0
  case eUnforgeableAttribute:
1641
0
    if (!IsInstance(type)) {
1642
0
      return true;
1643
0
    }
1644
0
    break;
1645
0
  case eConstant:
1646
0
    if (IsInstance(type)) {
1647
0
      return true;
1648
0
    }
1649
0
    break;
1650
0
  }
1651
0
1652
0
  switch (propertyInfo.type) {
1653
0
  RESOLVE_CASE(StaticMethod, JSFunctionSpec, XrayResolveMethod)
1654
0
  RESOLVE_CASE(StaticAttribute, JSPropertySpec, XrayResolveAttribute)
1655
0
  RESOLVE_CASE(Method, JSFunctionSpec, XrayResolveMethod)
1656
0
  RESOLVE_CASE(Attribute, JSPropertySpec, XrayResolveAttribute)
1657
0
  RESOLVE_CASE(UnforgeableMethod, JSFunctionSpec, XrayResolveMethod)
1658
0
  RESOLVE_CASE(UnforgeableAttribute, JSPropertySpec, XrayResolveAttribute)
1659
0
  RESOLVE_CASE(Constant, ConstantSpec, XrayResolveConstant)
1660
0
  }
1661
0
1662
0
  return true;
1663
0
}
1664
1665
#undef RESOLVE_CASE
1666
1667
static bool
1668
ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
1669
                              JS::Handle<JSObject*> obj,
1670
                              size_t protoAndIfaceCacheIndex, unsigned attrs,
1671
                              JS::MutableHandle<JS::PropertyDescriptor> desc,
1672
                              bool& cacheOnHolder)
1673
0
{
1674
0
  JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
1675
0
  {
1676
0
    JSAutoRealm ar(cx, global);
1677
0
    ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
1678
0
    // This function is called when resolving the "constructor" and "prototype"
1679
0
    // properties of Xrays for DOM prototypes and constructors respectively.
1680
0
    // This means the relevant Xray exists, which means its _target_ exists.
1681
0
    // And that means we managed to successfullly create the prototype or
1682
0
    // constructor, respectively, and hence must have managed to create the
1683
0
    // thing it's pointing to as well.  So our entry slot must exist.
1684
0
    JSObject* protoOrIface =
1685
0
      protoAndIfaceCache.EntrySlotMustExist(protoAndIfaceCacheIndex);
1686
0
    MOZ_RELEASE_ASSERT(protoOrIface, "How can this object not exist?");
1687
0
1688
0
    cacheOnHolder = true;
1689
0
1690
0
    desc.object().set(wrapper);
1691
0
    desc.setAttributes(attrs);
1692
0
    desc.setGetter(nullptr);
1693
0
    desc.setSetter(nullptr);
1694
0
    desc.value().set(JS::ObjectValue(*protoOrIface));
1695
0
  }
1696
0
  return JS_WrapPropertyDescriptor(cx, desc);
1697
0
}
1698
1699
#ifdef DEBUG
1700
1701
static void
1702
DEBUG_CheckXBLCallable(JSContext *cx, JSObject *obj)
1703
{
1704
    // In general, we shouldn't have cross-compartment wrappers here, because
1705
    // we should be running in an XBL scope, and the content prototype should
1706
    // contain wrappers to functions defined in the XBL scope. But if the node
1707
    // has been adopted into another compartment, those prototypes will now point
1708
    // to a different XBL scope (which is ok).
1709
    MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(obj),
1710
                  xpc::IsInContentXBLScope(js::UncheckedUnwrap(obj)));
1711
    MOZ_ASSERT(JS::IsCallable(obj));
1712
}
1713
1714
static void
1715
DEBUG_CheckXBLLookup(JSContext *cx, JS::PropertyDescriptor *desc)
1716
{
1717
    if (!desc->obj)
1718
        return;
1719
    if (!desc->value.isUndefined()) {
1720
        MOZ_ASSERT(desc->value.isObject());
1721
        DEBUG_CheckXBLCallable(cx, &desc->value.toObject());
1722
    }
1723
    if (desc->getter) {
1724
        MOZ_ASSERT(desc->attrs & JSPROP_GETTER);
1725
        DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter));
1726
    }
1727
    if (desc->setter) {
1728
        MOZ_ASSERT(desc->attrs & JSPROP_SETTER);
1729
        DEBUG_CheckXBLCallable(cx, JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter));
1730
    }
1731
}
1732
#else
1733
0
#define DEBUG_CheckXBLLookup(a, b) {}
1734
#endif
1735
1736
/* static */ bool
1737
XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
1738
                       JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1739
                       JS::MutableHandle<JS::PropertyDescriptor> desc,
1740
                       bool& cacheOnHolder)
1741
0
{
1742
0
  cacheOnHolder = false;
1743
0
1744
0
  DOMObjectType type;
1745
0
  const NativePropertyHooks *nativePropertyHooks =
1746
0
    GetNativePropertyHooks(cx, obj, type);
1747
0
  ResolveOwnProperty resolveOwnProperty =
1748
0
    nativePropertyHooks->mResolveOwnProperty;
1749
0
1750
0
  if (type == eNamedPropertiesObject) {
1751
0
    MOZ_ASSERT(!resolveOwnProperty,
1752
0
               "Shouldn't have any Xray-visible properties");
1753
0
    return true;
1754
0
  }
1755
0
1756
0
  const NativePropertiesHolder& nativePropertiesHolder =
1757
0
    nativePropertyHooks->mNativeProperties;
1758
0
  const NativeProperties* nativeProperties = nullptr;
1759
0
  const PropertyInfo* found = nullptr;
1760
0
1761
0
  if ((nativeProperties = nativePropertiesHolder.regular)) {
1762
0
    found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
1763
0
  }
1764
0
  if (!found &&
1765
0
      (nativeProperties = nativePropertiesHolder.chromeOnly) &&
1766
0
      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper))) {
1767
0
    found = XrayFindOwnPropertyInfo(cx, id, nativeProperties);
1768
0
  }
1769
0
1770
0
  if (IsInstance(type)) {
1771
0
    // Check for unforgeable properties first to prevent names provided by
1772
0
    // resolveOwnProperty callback from shadowing them.
1773
0
    if (found && (found->type == eUnforgeableMethod ||
1774
0
                  found->type == eUnforgeableAttribute)) {
1775
0
      if (!XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
1776
0
                               nativeProperties, *found)) {
1777
0
        return false;
1778
0
      }
1779
0
1780
0
      if (desc.object()) {
1781
0
        return true;
1782
0
      }
1783
0
    }
1784
0
1785
0
    if (resolveOwnProperty) {
1786
0
      if (!resolveOwnProperty(cx, wrapper, obj, id, desc)) {
1787
0
        return false;
1788
0
      }
1789
0
1790
0
      if (desc.object()) {
1791
0
        // None of these should be cached on the holder, since they're dynamic.
1792
0
        return true;
1793
0
      }
1794
0
    }
1795
0
1796
0
    // If we're a special scope for in-content XBL, our script expects to see
1797
0
    // the bound XBL methods and attributes when accessing content. However,
1798
0
    // these members are implemented in content via custom-spliced prototypes,
1799
0
    // and thus aren't visible through Xray wrappers unless we handle them
1800
0
    // explicitly. So we check if we're running in such a scope, and if so,
1801
0
    // whether the wrappee is a bound element. If it is, we do a lookup via
1802
0
    // specialized XBL machinery.
1803
0
    //
1804
0
    // While we have to do some sketchy walking through content land, we should
1805
0
    // be protected by read-only/non-configurable properties, and any functions
1806
0
    // we end up with should _always_ be living in our own scope (the XBL scope).
1807
0
    // Make sure to assert that.
1808
0
    JS::Rooted<JSObject*> maybeElement(cx, obj);
1809
0
    Element* element;
1810
0
    if (xpc::IsInContentXBLScope(wrapper) &&
1811
0
        NS_SUCCEEDED(UNWRAP_OBJECT(Element, &maybeElement, element))) {
1812
0
      if (!nsContentUtils::LookupBindingMember(cx, element, id, desc)) {
1813
0
        return false;
1814
0
      }
1815
0
1816
0
      DEBUG_CheckXBLLookup(cx, desc.address());
1817
0
1818
0
      if (desc.object()) {
1819
0
        // XBL properties shouldn't be cached on the holder, as they might be
1820
0
        // shadowed by own properties returned from mResolveOwnProperty.
1821
0
        desc.object().set(wrapper);
1822
0
1823
0
        return true;
1824
0
      }
1825
0
    }
1826
0
1827
0
    // For non-global instance Xrays there are no other properties, so return
1828
0
    // here for them.
1829
0
    if (type != eGlobalInstance) {
1830
0
      return true;
1831
0
    }
1832
0
  } else if (type == eInterface) {
1833
0
    if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PROTOTYPE)) {
1834
0
      return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
1835
0
             ResolvePrototypeOrConstructor(cx, wrapper, obj,
1836
0
                                           nativePropertyHooks->mPrototypeID,
1837
0
                                           JSPROP_PERMANENT | JSPROP_READONLY,
1838
0
                                           desc, cacheOnHolder);
1839
0
    }
1840
0
1841
0
    if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_ISINSTANCE) &&
1842
0
        DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
1843
0
          wantsInterfaceHasInstance) {
1844
0
      cacheOnHolder = true;
1845
0
      JSNativeWrapper interfaceIsInstanceWrapper = { InterfaceIsInstance,
1846
0
                                                      nullptr };
1847
0
      JSObject* funObj = XrayCreateFunction(cx, wrapper,
1848
0
                                            interfaceIsInstanceWrapper, 1, id);
1849
0
      if (!funObj) {
1850
0
        return false;
1851
0
      }
1852
0
1853
0
      desc.value().setObject(*funObj);
1854
0
      desc.setAttributes(0);
1855
0
      desc.object().set(wrapper);
1856
0
      desc.setSetter(nullptr);
1857
0
      desc.setGetter(nullptr);
1858
0
      return true;
1859
0
    }
1860
0
1861
0
    if (id == SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::hasInstance)) &&
1862
0
        DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj))->
1863
0
          wantsInterfaceHasInstance) {
1864
0
      cacheOnHolder = true;
1865
0
      JSNativeWrapper interfaceHasInstanceWrapper = { InterfaceHasInstance,
1866
0
                                                      nullptr };
1867
0
      JSObject* funObj = XrayCreateFunction(cx, wrapper,
1868
0
                                            interfaceHasInstanceWrapper, 1, id);
1869
0
      if (!funObj) {
1870
0
        return false;
1871
0
      }
1872
0
1873
0
      desc.value().setObject(*funObj);
1874
0
      desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT);
1875
0
      desc.object().set(wrapper);
1876
0
      desc.setSetter(nullptr);
1877
0
      desc.setGetter(nullptr);
1878
0
      return true;
1879
0
    }
1880
0
  } else {
1881
0
    MOZ_ASSERT(IsInterfacePrototype(type));
1882
0
1883
0
    if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_CONSTRUCTOR)) {
1884
0
      return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
1885
0
             ResolvePrototypeOrConstructor(cx, wrapper, obj,
1886
0
                                           nativePropertyHooks->mConstructorID,
1887
0
                                           0, desc, cacheOnHolder);
1888
0
    }
1889
0
1890
0
    // The properties for globals live on the instance, so return here as there
1891
0
    // are no properties on their interface prototype object.
1892
0
    if (type == eGlobalInterfacePrototype) {
1893
0
      return true;
1894
0
    }
1895
0
  }
1896
0
1897
0
  if (found &&
1898
0
      !XrayResolveProperty(cx, wrapper, obj, id, desc, cacheOnHolder, type,
1899
0
                           nativeProperties, *found)) {
1900
0
    return false;
1901
0
  }
1902
0
1903
0
  return true;
1904
0
}
1905
1906
bool
1907
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
1908
                   JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1909
                   JS::Handle<JS::PropertyDescriptor> desc,
1910
                   JS::ObjectOpResult &result, bool *defined)
1911
0
{
1912
0
  if (!js::IsProxy(obj))
1913
0
    return true;
1914
0
1915
0
  const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
1916
0
  return handler->defineProperty(cx, wrapper, id, desc, result, defined);
1917
0
}
1918
1919
template<typename SpecType>
1920
bool
1921
XrayAppendPropertyKeys(JSContext* cx, JS::Handle<JSObject*> obj,
1922
                       const Prefable<const SpecType>* pref,
1923
                       const PropertyInfo* infos, unsigned flags,
1924
                       JS::AutoIdVector& props)
1925
0
{
1926
0
  do {
1927
0
    bool prefIsEnabled = pref->isEnabled(cx, obj);
1928
0
    if (prefIsEnabled) {
1929
0
      const SpecType* spec = pref->specs;
1930
0
      do {
1931
0
        const jsid id = infos++->Id();
1932
0
        if (((flags & JSITER_HIDDEN) ||
1933
0
             (spec->flags & JSPROP_ENUMERATE)) &&
1934
0
            ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(id)) &&
1935
0
            !props.append(id)) {
1936
0
          return false;
1937
0
        }
1938
0
      } while ((++spec)->name);
1939
0
    }
1940
0
    // Break if we have reached the end of pref.
1941
0
    if (!(++pref)->specs) {
1942
0
      break;
1943
0
    }
1944
0
    // Advance infos if the previous pref is disabled. The -1 is required
1945
0
    // because there is an end-of-list terminator between pref->specs and
1946
0
    // (pref - 1)->specs.
1947
0
    if (!prefIsEnabled) {
1948
0
      infos += pref->specs - (pref - 1)->specs - 1;
1949
0
    }
1950
0
  } while (1);
1951
0
1952
0
  return true;
1953
0
}
Unexecuted instantiation: bool mozilla::dom::XrayAppendPropertyKeys<JSFunctionSpec>(JSContext*, JS::Handle<JSObject*>, mozilla::dom::Prefable<JSFunctionSpec const> const*, mozilla::dom::PropertyInfo const*, unsigned int, JS::AutoVector<jsid>&)
Unexecuted instantiation: bool mozilla::dom::XrayAppendPropertyKeys<JSPropertySpec>(JSContext*, JS::Handle<JSObject*>, mozilla::dom::Prefable<JSPropertySpec const> const*, mozilla::dom::PropertyInfo const*, unsigned int, JS::AutoVector<jsid>&)
1954
1955
template<>
1956
bool
1957
XrayAppendPropertyKeys<ConstantSpec>(JSContext* cx, JS::Handle<JSObject*> obj,
1958
                                     const Prefable<const ConstantSpec>* pref,
1959
                                     const PropertyInfo* infos, unsigned flags,
1960
                                     JS::AutoIdVector& props)
1961
0
{
1962
0
  do {
1963
0
    bool prefIsEnabled = pref->isEnabled(cx, obj);
1964
0
    if (prefIsEnabled) {
1965
0
      const ConstantSpec* spec = pref->specs;
1966
0
      do {
1967
0
        if (!props.append(infos++->Id())) {
1968
0
          return false;
1969
0
        }
1970
0
      } while ((++spec)->name);
1971
0
    }
1972
0
    // Break if we have reached the end of pref.
1973
0
    if (!(++pref)->specs) {
1974
0
      break;
1975
0
    }
1976
0
    // Advance infos if the previous pref is disabled. The -1 is required
1977
0
    // because there is an end-of-list terminator between pref->specs and
1978
0
    // (pref - 1)->specs.
1979
0
    if (!prefIsEnabled) {
1980
0
      infos += pref->specs - (pref - 1)->specs - 1;
1981
0
    }
1982
0
  } while (1);
1983
0
1984
0
  return true;
1985
0
}
1986
1987
0
#define ADD_KEYS_IF_DEFINED(FieldName) {                                        \
1988
0
  if (nativeProperties->Has##FieldName##s() &&                                  \
1989
0
      !XrayAppendPropertyKeys(cx, obj,                                          \
1990
0
                              nativeProperties->FieldName##s(),                 \
1991
0
                              nativeProperties->FieldName##PropertyInfos(),     \
1992
0
                              flags, props)) {                                  \
1993
0
    return false;                                                               \
1994
0
  }                                                                             \
1995
0
}
1996
1997
bool
1998
XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
1999
                    JS::Handle<JSObject*> obj,
2000
                    unsigned flags, JS::AutoIdVector& props,
2001
                    DOMObjectType type,
2002
                    const NativeProperties* nativeProperties)
2003
0
{
2004
0
  MOZ_ASSERT(type != eNamedPropertiesObject);
2005
0
2006
0
  if (IsInstance(type)) {
2007
0
    ADD_KEYS_IF_DEFINED(UnforgeableMethod);
2008
0
    ADD_KEYS_IF_DEFINED(UnforgeableAttribute);
2009
0
    if (type == eGlobalInstance) {
2010
0
      ADD_KEYS_IF_DEFINED(Method);
2011
0
      ADD_KEYS_IF_DEFINED(Attribute);
2012
0
    }
2013
0
  } else {
2014
0
    MOZ_ASSERT(type != eGlobalInterfacePrototype);
2015
0
    if (type == eInterface) {
2016
0
      ADD_KEYS_IF_DEFINED(StaticMethod);
2017
0
      ADD_KEYS_IF_DEFINED(StaticAttribute);
2018
0
    } else {
2019
0
      MOZ_ASSERT(type == eInterfacePrototype);
2020
0
      ADD_KEYS_IF_DEFINED(Method);
2021
0
      ADD_KEYS_IF_DEFINED(Attribute);
2022
0
    }
2023
0
    ADD_KEYS_IF_DEFINED(Constant);
2024
0
  }
2025
0
2026
0
  return true;
2027
0
}
2028
2029
#undef ADD_KEYS_IF_DEFINED
2030
2031
bool
2032
XrayOwnNativePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
2033
                          const NativePropertyHooks* nativePropertyHooks,
2034
                          DOMObjectType type, JS::Handle<JSObject*> obj,
2035
                          unsigned flags, JS::AutoIdVector& props)
2036
0
{
2037
0
  MOZ_ASSERT(type != eNamedPropertiesObject);
2038
0
2039
0
  if (type == eInterface &&
2040
0
      nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count &&
2041
0
      !AddStringToIDVector(cx, props, "prototype")) {
2042
0
    return false;
2043
0
  }
2044
0
2045
0
  if (IsInterfacePrototype(type) &&
2046
0
      nativePropertyHooks->mConstructorID != constructors::id::_ID_Count &&
2047
0
      (flags & JSITER_HIDDEN) &&
2048
0
      !AddStringToIDVector(cx, props, "constructor")) {
2049
0
    return false;
2050
0
  }
2051
0
2052
0
  const NativePropertiesHolder& nativeProperties =
2053
0
    nativePropertyHooks->mNativeProperties;
2054
0
2055
0
  if (nativeProperties.regular &&
2056
0
      !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
2057
0
                           nativeProperties.regular)) {
2058
0
    return false;
2059
0
  }
2060
0
2061
0
  if (nativeProperties.chromeOnly &&
2062
0
      xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
2063
0
      !XrayOwnPropertyKeys(cx, wrapper, obj, flags, props, type,
2064
0
                           nativeProperties.chromeOnly)) {
2065
0
    return false;
2066
0
  }
2067
0
2068
0
  return true;
2069
0
}
2070
2071
bool
2072
XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
2073
                    JS::Handle<JSObject*> obj,
2074
                    unsigned flags, JS::AutoIdVector& props)
2075
0
{
2076
0
  DOMObjectType type;
2077
0
  const NativePropertyHooks* nativePropertyHooks =
2078
0
    GetNativePropertyHooks(cx, obj, type);
2079
0
  EnumerateOwnProperties enumerateOwnProperties =
2080
0
    nativePropertyHooks->mEnumerateOwnProperties;
2081
0
2082
0
  if (type == eNamedPropertiesObject) {
2083
0
    MOZ_ASSERT(!enumerateOwnProperties,
2084
0
               "Shouldn't have any Xray-visible properties");
2085
0
    return true;
2086
0
  }
2087
0
2088
0
  if (IsInstance(type)) {
2089
0
    // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1071189
2090
0
    //       Should do something about XBL properties too.
2091
0
    if (enumerateOwnProperties &&
2092
0
        !enumerateOwnProperties(cx, wrapper, obj, props)) {
2093
0
      return false;
2094
0
    }
2095
0
  }
2096
0
2097
0
  return type == eGlobalInterfacePrototype ||
2098
0
         XrayOwnNativePropertyKeys(cx, wrapper, nativePropertyHooks, type,
2099
0
                                   obj, flags, props);
2100
0
}
2101
2102
const JSClass*
2103
XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj)
2104
0
{
2105
0
  DOMObjectType type;
2106
0
  const NativePropertyHooks* nativePropertyHooks =
2107
0
    GetNativePropertyHooks(cx, obj, type);
2108
0
  if (!IsInstance(type)) {
2109
0
    // Non-instances don't need any special expando classes.
2110
0
    return &DefaultXrayExpandoObjectClass;
2111
0
  }
2112
0
2113
0
  return nativePropertyHooks->mXrayExpandoClass;
2114
0
}
2115
2116
bool
2117
XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2118
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
2119
                        JS::ObjectOpResult& opresult)
2120
0
{
2121
0
  DOMObjectType type;
2122
0
  const NativePropertyHooks* nativePropertyHooks =
2123
0
    GetNativePropertyHooks(cx, obj, type);
2124
0
  if (!IsInstance(type) || !nativePropertyHooks->mDeleteNamedProperty) {
2125
0
    return opresult.succeed();
2126
0
  }
2127
0
  return nativePropertyHooks->mDeleteNamedProperty(cx, wrapper, obj, id,
2128
0
                                                   opresult);
2129
0
}
2130
2131
JSObject*
2132
GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
2133
                               bool* isXray)
2134
0
{
2135
0
  if (!xpc::WrapperFactory::IsXrayWrapper(obj)) {
2136
0
    JSObject* retval = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
2137
0
    MOZ_ASSERT(IsDOMObject(retval));
2138
0
    *isXray = false;
2139
0
    return retval;
2140
0
  }
2141
0
2142
0
  *isXray = true;
2143
0
  return xpc::EnsureXrayExpandoObject(cx, obj);;
2144
0
}
2145
2146
DEFINE_XRAY_EXPANDO_CLASS(, DefaultXrayExpandoObjectClass, 0);
2147
2148
NativePropertyHooks sEmptyNativePropertyHooks = {
2149
  nullptr,
2150
  nullptr,
2151
  nullptr,
2152
  {
2153
    nullptr,
2154
    nullptr
2155
  },
2156
  prototypes::id::_ID_Count,
2157
  constructors::id::_ID_Count,
2158
  nullptr
2159
};
2160
2161
const js::ClassOps sBoringInterfaceObjectClassClassOps = {
2162
    nullptr,               /* addProperty */
2163
    nullptr,               /* delProperty */
2164
    nullptr,               /* enumerate */
2165
    nullptr,               /* newEnumerate */
2166
    nullptr,               /* resolve */
2167
    nullptr,               /* mayResolve */
2168
    nullptr,               /* finalize */
2169
    ThrowingConstructor,   /* call */
2170
    nullptr,               /* hasInstance */
2171
    ThrowingConstructor,   /* construct */
2172
    nullptr,               /* trace */
2173
};
2174
2175
const js::ObjectOps sInterfaceObjectClassObjectOps = {
2176
  nullptr, /* lookupProperty */
2177
  nullptr, /* defineProperty */
2178
  nullptr, /* hasProperty */
2179
  nullptr, /* getProperty */
2180
  nullptr, /* setProperty */
2181
  nullptr, /* getOwnPropertyDescriptor */
2182
  nullptr, /* deleteProperty */
2183
  nullptr, /* getElements */
2184
  InterfaceObjectToString, /* funToString */
2185
};
2186
2187
bool
2188
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
2189
                       JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
2190
                       bool* found, JS::MutableHandle<JS::Value> vp)
2191
0
{
2192
0
  JS::Rooted<JSObject*> proto(cx);
2193
0
  if (!js::GetObjectProto(cx, proxy, &proto)) {
2194
0
    return false;
2195
0
  }
2196
0
  if (!proto) {
2197
0
    *found = false;
2198
0
    return true;
2199
0
  }
2200
0
2201
0
  if (!JS_HasPropertyById(cx, proto, id, found)) {
2202
0
    return false;
2203
0
  }
2204
0
2205
0
  if (!*found) {
2206
0
    return true;
2207
0
  }
2208
0
2209
0
  return JS_ForwardGetPropertyTo(cx, proto, id, receiver, vp);
2210
0
}
2211
2212
bool
2213
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
2214
                       JS::Handle<jsid> id, bool* has)
2215
0
{
2216
0
  JS::Rooted<JSObject*> proto(cx);
2217
0
  if (!js::GetObjectProto(cx, proxy, &proto)) {
2218
0
    return false;
2219
0
  }
2220
0
  if (!proto) {
2221
0
    *has = false;
2222
0
    return true;
2223
0
  }
2224
0
2225
0
  return JS_HasPropertyById(cx, proto, id, has);
2226
0
}
2227
2228
bool
2229
AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
2230
                       nsTArray<nsString>& names,
2231
                       bool shadowPrototypeProperties,
2232
                       JS::AutoIdVector& props)
2233
0
{
2234
0
  for (uint32_t i = 0; i < names.Length(); ++i) {
2235
0
    JS::Rooted<JS::Value> v(cx);
2236
0
    if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
2237
0
      return false;
2238
0
    }
2239
0
2240
0
    JS::Rooted<jsid> id(cx);
2241
0
    if (!JS_ValueToId(cx, v, &id)) {
2242
0
      return false;
2243
0
    }
2244
0
2245
0
    bool shouldAppend = shadowPrototypeProperties;
2246
0
    if (!shouldAppend) {
2247
0
      bool has;
2248
0
      if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
2249
0
        return false;
2250
0
      }
2251
0
      shouldAppend = !has;
2252
0
    }
2253
0
2254
0
    if (shouldAppend) {
2255
0
      if (!props.append(id)) {
2256
0
        return false;
2257
0
      }
2258
0
    }
2259
0
  }
2260
0
2261
0
  return true;
2262
0
}
2263
2264
bool
2265
DictionaryBase::ParseJSON(JSContext* aCx,
2266
                          const nsAString& aJSON,
2267
                          JS::MutableHandle<JS::Value> aVal)
2268
0
{
2269
0
  if (aJSON.IsEmpty()) {
2270
0
    return true;
2271
0
  }
2272
0
  return JS_ParseJSON(aCx, PromiseFlatString(aJSON).get(), aJSON.Length(), aVal);
2273
0
}
2274
2275
bool
2276
DictionaryBase::StringifyToJSON(JSContext* aCx,
2277
                                JS::Handle<JSObject*> aObj,
2278
                                nsAString& aJSON) const
2279
0
{
2280
0
  return JS::ToJSONMaybeSafely(aCx, aObj, AppendJSONToString, &aJSON);
2281
0
}
2282
2283
/* static */
2284
bool
2285
DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
2286
                                   uint32_t aDataLength,
2287
                                   void* aString)
2288
0
{
2289
0
  nsAString* string = static_cast<nsAString*>(aString);
2290
0
  string->Append(aJSONData, aDataLength);
2291
0
  return true;
2292
0
}
2293
2294
void
2295
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg, ErrorResult& aError)
2296
0
{
2297
0
  js::AssertSameCompartment(aCx, aObjArg);
2298
0
2299
0
  aError.MightThrowJSException();
2300
0
2301
0
  // Check if we're anywhere near the stack limit before we reach the
2302
0
  // transplanting code, since it has no good way to handle errors. This uses
2303
0
  // the untrusted script limit, which is not strictly necessary since no
2304
0
  // actual script should run.
2305
0
  if (!js::CheckRecursionLimitConservative(aCx)) {
2306
0
    aError.StealExceptionFromJSContext(aCx);
2307
0
    return;
2308
0
  }
2309
0
2310
0
  JS::Rooted<JSObject*> aObj(aCx, aObjArg);
2311
0
  const DOMJSClass* domClass = GetDOMClass(aObj);
2312
0
2313
0
  // DOM things are always parented to globals.
2314
0
  JS::Rooted<JSObject*> oldParent(aCx, JS::GetNonCCWObjectGlobal(aObj));
2315
0
  MOZ_ASSERT(JS_IsGlobalObject(oldParent));
2316
0
2317
0
  JS::Rooted<JSObject*> newParent(aCx,
2318
0
                                  domClass->mGetAssociatedGlobal(aCx, aObj));
2319
0
  MOZ_ASSERT(JS_IsGlobalObject(newParent));
2320
0
2321
0
  JSAutoRealm oldAr(aCx, oldParent);
2322
0
2323
0
  JS::Compartment* oldCompartment = js::GetObjectCompartment(oldParent);
2324
0
  JS::Compartment* newCompartment = js::GetObjectCompartment(newParent);
2325
0
  if (oldCompartment == newCompartment) {
2326
0
    MOZ_ASSERT(oldParent == newParent);
2327
0
    return;
2328
0
  }
2329
0
2330
0
  nsISupports* native = UnwrapDOMObjectToISupports(aObj);
2331
0
  if (!native) {
2332
0
    return;
2333
0
  }
2334
0
2335
0
  bool isProxy = js::IsProxy(aObj);
2336
0
  JS::Rooted<JSObject*> expandoObject(aCx);
2337
0
  if (isProxy) {
2338
0
    expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
2339
0
  }
2340
0
2341
0
  JSAutoRealm newAr(aCx, newParent);
2342
0
2343
0
  // First we clone the reflector. We get a copy of its properties and clone its
2344
0
  // expando chain.
2345
0
2346
0
  JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx);
2347
0
  if (!proto) {
2348
0
    aError.StealExceptionFromJSContext(aCx);
2349
0
    return;
2350
0
  }
2351
0
2352
0
  JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto));
2353
0
  if (!newobj) {
2354
0
    aError.StealExceptionFromJSContext(aCx);
2355
0
    return;
2356
0
  }
2357
0
2358
0
  JS::Rooted<JSObject*> propertyHolder(aCx);
2359
0
  JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj);
2360
0
  if (copyFrom) {
2361
0
    propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr);
2362
0
    if (!propertyHolder) {
2363
0
      aError.StealExceptionFromJSContext(aCx);
2364
0
      return;
2365
0
    }
2366
0
2367
0
    if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) {
2368
0
      aError.StealExceptionFromJSContext(aCx);
2369
0
      return;
2370
0
    }
2371
0
  } else {
2372
0
    propertyHolder = nullptr;
2373
0
  }
2374
0
2375
0
  // We've set up |newobj|, so we make it own the native by setting its reserved
2376
0
  // slot and nulling out the reserved slot of |obj|.
2377
0
  //
2378
0
  // NB: It's important to do this _after_ copying the properties to
2379
0
  // propertyHolder. Otherwise, an object with |foo.x === foo| will
2380
0
  // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
2381
0
  js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
2382
0
                      js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
2383
0
  js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
2384
0
2385
0
  aObj = xpc::TransplantObjectRetainingXrayExpandos(aCx, aObj, newobj);
2386
0
  if (!aObj) {
2387
0
    MOZ_CRASH();
2388
0
  }
2389
0
2390
0
  nsWrapperCache* cache = nullptr;
2391
0
  CallQueryInterface(native, &cache);
2392
0
  bool preserving = cache->PreservingWrapper();
2393
0
  cache->SetPreservingWrapper(false);
2394
0
  cache->SetWrapper(aObj);
2395
0
  cache->SetPreservingWrapper(preserving);
2396
0
2397
0
  if (propertyHolder) {
2398
0
    JS::Rooted<JSObject*> copyTo(aCx);
2399
0
    if (isProxy) {
2400
0
      copyTo = DOMProxyHandler::EnsureExpandoObject(aCx, aObj);
2401
0
    } else {
2402
0
      copyTo = aObj;
2403
0
    }
2404
0
2405
0
    if (!copyTo || !JS_CopyPropertiesFrom(aCx, copyTo, propertyHolder)) {
2406
0
      MOZ_CRASH();
2407
0
    }
2408
0
  }
2409
0
2410
0
  JS::Rooted<JSObject*> maybeObjLC(aCx, aObj);
2411
0
  nsObjectLoadingContent* htmlobject;
2412
0
  nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, &maybeObjLC, htmlobject);
2413
0
  if (NS_FAILED(rv)) {
2414
0
    rv = UNWRAP_OBJECT(HTMLEmbedElement, &maybeObjLC, htmlobject);
2415
0
    if (NS_FAILED(rv)) {
2416
0
      htmlobject = nullptr;
2417
0
    }
2418
0
  }
2419
0
  if (htmlobject) {
2420
0
    htmlobject->SetupProtoChain(aCx, aObj);
2421
0
  }
2422
0
}
2423
2424
GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
2425
  : mGlobalJSObject(aCx),
2426
    mCx(aCx),
2427
    mGlobalObject(nullptr)
2428
14
{
2429
14
  MOZ_ASSERT(mCx);
2430
14
  JS::Rooted<JSObject*> obj(aCx, aObject);
2431
14
  if (js::IsWrapper(obj)) {
2432
0
    obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
2433
0
    if (!obj) {
2434
0
      // We should never end up here on a worker thread, since there shouldn't
2435
0
      // be any security wrappers to worry about.
2436
0
      if (!MOZ_LIKELY(NS_IsMainThread())) {
2437
0
        MOZ_CRASH();
2438
0
      }
2439
0
2440
0
      Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
2441
0
      return;
2442
14
    }
2443
0
  }
2444
14
2445
14
  mGlobalJSObject = JS::GetNonCCWObjectGlobal(obj);
2446
14
}
2447
2448
nsISupports*
2449
GlobalObject::GetAsSupports() const
2450
0
{
2451
0
  if (mGlobalObject) {
2452
0
    return mGlobalObject;
2453
0
  }
2454
0
2455
0
  MOZ_ASSERT(!js::IsWrapper(mGlobalJSObject));
2456
0
2457
0
  // Most of our globals are DOM objects.  Try that first.  Note that this
2458
0
  // assumes that either the first nsISupports in the object is the canonical
2459
0
  // one or that we don't care about the canonical nsISupports here.
2460
0
  mGlobalObject = UnwrapDOMObjectToISupports(mGlobalJSObject);
2461
0
  if (mGlobalObject) {
2462
0
    return mGlobalObject;
2463
0
  }
2464
0
2465
0
  MOZ_ASSERT(NS_IsMainThread(), "All our worker globals are DOM objects");
2466
0
2467
0
  // Remove everything below here once all our global objects are using new
2468
0
  // bindings.  If that ever happens; it would need to include Sandbox and
2469
0
  // BackstagePass.
2470
0
2471
0
  // See whether mGlobalJSObject is an XPCWrappedNative.  This will redo the
2472
0
  // IsWrapper bit above and the UnwrapDOMObjectToISupports in the case when
2473
0
  // we're not actually an XPCWrappedNative, but this should be a rare-ish case
2474
0
  // anyway.
2475
0
  nsCOMPtr<nsISupports> supp = xpc::UnwrapReflectorToISupports(mGlobalJSObject);
2476
0
  if (supp) {
2477
0
    // See documentation for mGlobalJSObject for why this assignment is OK.
2478
0
    mGlobalObject = supp;
2479
0
    return mGlobalObject;
2480
0
  }
2481
0
2482
0
  // And now a final hack.  Sandbox is not a reflector, but it does have an
2483
0
  // nsIGlobalObject hanging out in its private slot.  Handle that case here,
2484
0
  // (though again, this will do the useless UnwrapDOMObjectToISupports if we
2485
0
  // got here for something that is somehow not a DOM object, not an
2486
0
  // XPCWrappedNative _and_ not a Sandbox).
2487
0
  if (XPCConvert::GetISupportsFromJSObject(mGlobalJSObject, &mGlobalObject)) {
2488
0
    return mGlobalObject;
2489
0
  }
2490
0
2491
0
  MOZ_ASSERT(!mGlobalObject);
2492
0
2493
0
  Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
2494
0
  return nullptr;
2495
0
}
2496
2497
nsIPrincipal*
2498
GlobalObject::GetSubjectPrincipal() const
2499
0
{
2500
0
  if (!NS_IsMainThread()) {
2501
0
    return nullptr;
2502
0
  }
2503
0
2504
0
  JS::Realm* realm = js::GetContextRealm(mCx);
2505
0
  MOZ_ASSERT(realm);
2506
0
  JSPrincipals* principals = JS::GetRealmPrincipals(realm);
2507
0
  return nsJSPrincipals::get(principals);
2508
0
}
2509
2510
CallerType
2511
GlobalObject::CallerType() const
2512
0
{
2513
0
  return nsContentUtils::ThreadsafeIsSystemCaller(mCx) ?
2514
0
    dom::CallerType::System : dom::CallerType::NonSystem;
2515
0
}
2516
2517
static bool
2518
CallOrdinaryHasInstance(JSContext* cx, JS::CallArgs& args)
2519
0
{
2520
0
    JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
2521
0
    bool isInstance;
2522
0
    if (!JS::OrdinaryHasInstance(cx, thisObj, args.get(0), &isInstance)) {
2523
0
      return false;
2524
0
    }
2525
0
    args.rval().setBoolean(isInstance);
2526
0
    return true;
2527
0
}
2528
2529
bool
2530
InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp)
2531
0
{
2532
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
2533
0
  // If the thing we were passed is not an object, return false like
2534
0
  // OrdinaryHasInstance does.
2535
0
  if (!args.get(0).isObject()) {
2536
0
    args.rval().setBoolean(false);
2537
0
    return true;
2538
0
  }
2539
0
2540
0
  // If "this" is not an object, likewise return false (again, like
2541
0
  // OrdinaryHasInstance).
2542
0
  if (!args.thisv().isObject()) {
2543
0
    args.rval().setBoolean(false);
2544
0
    return true;
2545
0
  }
2546
0
2547
0
  // If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
2548
0
  // constructor, so just fall back to OrdinaryHasInstance.  But note that we
2549
0
  // should CheckedUnwrap here, because otherwise we won't get the right
2550
0
  // answers.
2551
0
  JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
2552
0
  if (!thisObj) {
2553
0
    // Just fall back on the normal thing, in case it still happens to work.
2554
0
    return CallOrdinaryHasInstance(cx, args);
2555
0
  }
2556
0
2557
0
  const js::Class* thisClass = js::GetObjectClass(thisObj);
2558
0
2559
0
  if (!IsDOMIfaceAndProtoClass(thisClass)) {
2560
0
    return CallOrdinaryHasInstance(cx, args);
2561
0
  }
2562
0
2563
0
  const DOMIfaceAndProtoJSClass* clasp =
2564
0
    DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
2565
0
2566
0
  // If "this" isn't a DOM constructor or is a constructor for an interface
2567
0
  // without a prototype, just fall back to OrdinaryHasInstance.
2568
0
  if (clasp->mType != eInterface ||
2569
0
      clasp->mPrototypeID == prototypes::id::_ID_Count) {
2570
0
    return CallOrdinaryHasInstance(cx, args);
2571
0
  }
2572
0
2573
0
  JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
2574
0
  const DOMJSClass* domClass =
2575
0
    GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
2576
0
2577
0
  if (domClass &&
2578
0
      domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
2579
0
    args.rval().setBoolean(true);
2580
0
    return true;
2581
0
  }
2582
0
2583
0
  if (jsipc::IsWrappedCPOW(instance)) {
2584
0
    bool boolp = false;
2585
0
    if (!jsipc::DOMInstanceOf(cx, js::UncheckedUnwrap(instance), clasp->mPrototypeID,
2586
0
                              clasp->mDepth, &boolp)) {
2587
0
      return false;
2588
0
    }
2589
0
    args.rval().setBoolean(boolp);
2590
0
    return true;
2591
0
  }
2592
0
2593
0
  return CallOrdinaryHasInstance(cx, args);
2594
0
}
2595
2596
bool
2597
InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
2598
                     JS::Handle<JSObject*> instance,
2599
                     bool* bp)
2600
0
{
2601
0
  const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
2602
0
2603
0
  MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
2604
0
             "Why do we have a hasInstance hook if we don't have a prototype "
2605
0
             "ID?");
2606
0
2607
0
  *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
2608
0
  return true;
2609
0
}
2610
2611
bool
2612
InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp)
2613
0
{
2614
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
2615
0
2616
0
  // If the thing we were passed is not an object, return false.
2617
0
  if (!args.get(0).isObject()) {
2618
0
    args.rval().setBoolean(false);
2619
0
    return true;
2620
0
  }
2621
0
2622
0
  // If "this" isn't a DOM constructor or is a constructor for an interface
2623
0
  // without a prototype, return false.
2624
0
  if (!args.thisv().isObject()) {
2625
0
    args.rval().setBoolean(false);
2626
0
    return true;
2627
0
  }
2628
0
2629
0
  JS::Rooted<JSObject*> thisObj(cx, js::CheckedUnwrap(&args.thisv().toObject()));
2630
0
  if (!thisObj) {
2631
0
    args.rval().setBoolean(false);
2632
0
    return true;
2633
0
  }
2634
0
2635
0
  const js::Class* thisClass = js::GetObjectClass(thisObj);
2636
0
  if (!IsDOMIfaceAndProtoClass(thisClass)) {
2637
0
    args.rval().setBoolean(false);
2638
0
    return true;
2639
0
  }
2640
0
2641
0
  const DOMIfaceAndProtoJSClass* clasp =
2642
0
    DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
2643
0
2644
0
  if (clasp->mType != eInterface ||
2645
0
      clasp->mPrototypeID == prototypes::id::_ID_Count) {
2646
0
    args.rval().setBoolean(false);
2647
0
    return true;
2648
0
  }
2649
0
2650
0
  JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
2651
0
  const DOMJSClass* domClass =
2652
0
    GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
2653
0
2654
0
  bool isInstance =
2655
0
    domClass &&
2656
0
    domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID;
2657
0
2658
0
  args.rval().setBoolean(isInstance);
2659
0
  return true;
2660
0
}
2661
2662
bool
2663
ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj)
2664
0
{
2665
0
  JS::Rooted<JSObject*> rootedObj(cx, obj);
2666
0
  GlobalObject global(cx, rootedObj);
2667
0
  if (global.Failed()) {
2668
0
    return false;
2669
0
  }
2670
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
2671
0
  if (window && window->GetDoc()) {
2672
0
    window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
2673
0
  }
2674
0
  return true;
2675
0
}
2676
2677
bool
2678
GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
2679
                                       nsIGlobalObject** globalObj)
2680
0
{
2681
0
  // Be very careful to not get tricked here.
2682
0
  MOZ_ASSERT(NS_IsMainThread());
2683
0
  if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))) {
2684
0
    MOZ_CRASH("Should have a chrome object here");
2685
0
  }
2686
0
2687
0
  // Look up the content-side object.
2688
0
  JS::Rooted<JS::Value> domImplVal(cx);
2689
0
  if (!JS_GetProperty(cx, obj, "__DOM_IMPL__", &domImplVal)) {
2690
0
    return false;
2691
0
  }
2692
0
2693
0
  if (!domImplVal.isObject()) {
2694
0
    ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
2695
0
    return false;
2696
0
  }
2697
0
2698
0
  // Go ahead and get the global from it.  GlobalObject will handle
2699
0
  // doing unwrapping as needed.
2700
0
  GlobalObject global(cx, &domImplVal.toObject());
2701
0
  if (global.Failed()) {
2702
0
    return false;
2703
0
  }
2704
0
2705
0
  DebugOnly<nsresult> rv = CallQueryInterface(global.GetAsSupports(), globalObj);
2706
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
2707
0
  MOZ_ASSERT(*globalObj);
2708
0
  return true;
2709
0
}
2710
2711
already_AddRefed<nsIGlobalObject>
2712
ConstructJSImplementation(const char* aContractId,
2713
                          const GlobalObject& aGlobal,
2714
                          JS::MutableHandle<JSObject*> aObject,
2715
                          ErrorResult& aRv)
2716
0
{
2717
0
  // Get the global object to use as a parent and for initialization.
2718
0
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2719
0
  if (!global) {
2720
0
    aRv.Throw(NS_ERROR_FAILURE);
2721
0
    return nullptr;
2722
0
  }
2723
0
2724
0
  ConstructJSImplementation(aContractId, global, aObject, aRv);
2725
0
2726
0
  if (aRv.Failed()) {
2727
0
    return nullptr;
2728
0
  }
2729
0
  return global.forget();
2730
0
}
2731
2732
void
2733
ConstructJSImplementation(const char* aContractId,
2734
                          nsIGlobalObject* aGlobal,
2735
                          JS::MutableHandle<JSObject*> aObject,
2736
                          ErrorResult& aRv)
2737
0
{
2738
0
  MOZ_ASSERT(NS_IsMainThread());
2739
0
2740
0
  // Make sure to divorce ourselves from the calling JS while creating and
2741
0
  // initializing the object, so exceptions from that will get reported
2742
0
  // properly, since those are never exceptions that a spec wants to be thrown.
2743
0
  {
2744
0
    AutoNoJSAPI nojsapi;
2745
0
2746
0
    // Get the XPCOM component containing the JS implementation.
2747
0
    nsresult rv;
2748
0
    nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
2749
0
    if (!implISupports) {
2750
0
      nsPrintfCString msg("Failed to get JS implementation for contract \"%s\"",
2751
0
                          aContractId);
2752
0
      NS_WARNING(msg.get());
2753
0
      aRv.Throw(rv);
2754
0
      return;
2755
0
    }
2756
0
    // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer
2757
0
    // and our global is a window.
2758
0
    nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
2759
0
      do_QueryInterface(implISupports);
2760
0
    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
2761
0
    if (gpi) {
2762
0
      JS::Rooted<JS::Value> initReturn(RootingCx());
2763
0
      rv = gpi->Init(window, &initReturn);
2764
0
      if (NS_FAILED(rv)) {
2765
0
        aRv.Throw(rv);
2766
0
        return;
2767
0
      }
2768
0
      // With JS-implemented WebIDL, the return value of init() is not used to determine
2769
0
      // if init() failed, so init() should only return undefined. Any kind of permission
2770
0
      // or pref checking must happen by adding an attribute to the WebIDL interface.
2771
0
      if (!initReturn.isUndefined()) {
2772
0
        MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything");
2773
0
        MOZ_CRASH();
2774
0
      }
2775
0
    }
2776
0
    // Extract the JS implementation from the XPCOM object.
2777
0
    nsCOMPtr<nsIXPConnectWrappedJS> implWrapped =
2778
0
      do_QueryInterface(implISupports, &rv);
2779
0
    MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component.");
2780
0
    if (!implWrapped) {
2781
0
      aRv.Throw(rv);
2782
0
      return;
2783
0
    }
2784
0
    aObject.set(implWrapped->GetJSObject());
2785
0
    if (!aObject) {
2786
0
      aRv.Throw(NS_ERROR_FAILURE);
2787
0
    }
2788
0
  }
2789
0
}
2790
2791
bool
2792
NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
2793
                         JS::MutableHandle<JS::Value> rval)
2794
0
{
2795
0
    // ByteStrings are not UTF-8 encoded.
2796
0
    JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length());
2797
0
2798
0
    if (!jsStr)
2799
0
        return false;
2800
0
2801
0
    rval.setString(jsStr);
2802
0
    return true;
2803
0
}
2804
2805
void
2806
NormalizeUSVString(nsAString& aString)
2807
0
{
2808
0
  EnsureUTF16Validity(aString);
2809
0
}
2810
2811
void
2812
NormalizeUSVString(binding_detail::FakeString& aString)
2813
0
{
2814
0
  EnsureUTF16ValiditySpan(aString);
2815
0
}
2816
2817
bool
2818
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
2819
                           bool nullable, nsACString& result)
2820
0
{
2821
0
  JS::Rooted<JSString*> s(cx);
2822
0
  if (v.isString()) {
2823
0
    s = v.toString();
2824
0
  } else {
2825
0
2826
0
    if (nullable && v.isNullOrUndefined()) {
2827
0
      result.SetIsVoid(true);
2828
0
      return true;
2829
0
    }
2830
0
2831
0
    s = JS::ToString(cx, v);
2832
0
    if (!s) {
2833
0
      return false;
2834
0
    }
2835
0
  }
2836
0
2837
0
  // Conversion from Javascript string to ByteString is only valid if all
2838
0
  // characters < 256. This is always the case for Latin1 strings.
2839
0
  size_t length;
2840
0
  if (!js::StringHasLatin1Chars(s)) {
2841
0
    // ThrowErrorMessage can GC, so we first scan the string for bad chars
2842
0
    // and report the error outside the AutoCheckCannotGC scope.
2843
0
    bool foundBadChar = false;
2844
0
    size_t badCharIndex;
2845
0
    char16_t badChar;
2846
0
    {
2847
0
      JS::AutoCheckCannotGC nogc;
2848
0
      const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
2849
0
      if (!chars) {
2850
0
        return false;
2851
0
      }
2852
0
2853
0
      for (size_t i = 0; i < length; i++) {
2854
0
        if (chars[i] > 255) {
2855
0
          badCharIndex = i;
2856
0
          badChar = chars[i];
2857
0
          foundBadChar = true;
2858
0
          break;
2859
0
        }
2860
0
      }
2861
0
    }
2862
0
2863
0
    if (foundBadChar) {
2864
0
      MOZ_ASSERT(badCharIndex < length);
2865
0
      MOZ_ASSERT(badChar > 255);
2866
0
      // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
2867
0
      // 20 digits, plus one more for the null terminator.
2868
0
      char index[21];
2869
0
      static_assert(sizeof(size_t) <= 8, "index array too small");
2870
0
      SprintfLiteral(index, "%zu", badCharIndex);
2871
0
      // A char16_t is 16 bits long.  The biggest unsigned 16 bit
2872
0
      // number (65,535) has 5 digits, plus one more for the null
2873
0
      // terminator.
2874
0
      char badCharArray[6];
2875
0
      static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
2876
0
      SprintfLiteral(badCharArray, "%d", badChar);
2877
0
      ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
2878
0
      return false;
2879
0
    }
2880
0
  } else {
2881
0
    length = JS::GetStringLength(s);
2882
0
  }
2883
0
2884
0
  static_assert(js::MaxStringLength < UINT32_MAX,
2885
0
                "length+1 shouldn't overflow");
2886
0
2887
0
  if (!result.SetLength(length, fallible)) {
2888
0
    return false;
2889
0
  }
2890
0
2891
0
  if (!JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length)) {
2892
0
    return false;
2893
0
  }
2894
0
2895
0
  return true;
2896
0
}
2897
2898
void
2899
FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
2900
0
{
2901
0
  MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
2902
0
  mozilla::dom::DestroyProtoAndIfaceCache(aObj);
2903
0
}
2904
2905
bool
2906
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
2907
              JS::Handle<jsid> aId, bool* aResolvedp)
2908
50
{
2909
50
  MOZ_ASSERT(JS_IsGlobalObject(aObj),
2910
50
             "Should have a global here, since we plan to resolve standard "
2911
50
             "classes!");
2912
50
2913
50
  return JS_ResolveStandardClass(aCx, aObj, aId, aResolvedp);
2914
50
}
2915
2916
bool
2917
MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj)
2918
0
{
2919
0
  return JS_MayResolveStandardClass(aNames, aId, aMaybeObj);
2920
0
}
2921
2922
bool
2923
EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
2924
                JS::AutoIdVector& aProperties, bool aEnumerableOnly)
2925
0
{
2926
0
  MOZ_ASSERT(JS_IsGlobalObject(aObj),
2927
0
             "Should have a global here, since we plan to enumerate standard "
2928
0
             "classes!");
2929
0
2930
0
  return JS_NewEnumerateStandardClasses(aCx, aObj, aProperties,
2931
0
                                        aEnumerableOnly);
2932
0
}
2933
2934
bool
2935
IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
2936
                   uint32_t aNonExposedGlobals)
2937
4
{
2938
4
  MOZ_ASSERT(aNonExposedGlobals, "Why did we get called?");
2939
4
  MOZ_ASSERT((aNonExposedGlobals &
2940
4
              ~(GlobalNames::Window |
2941
4
                GlobalNames::BackstagePass |
2942
4
                GlobalNames::DedicatedWorkerGlobalScope |
2943
4
                GlobalNames::SharedWorkerGlobalScope |
2944
4
                GlobalNames::ServiceWorkerGlobalScope |
2945
4
                GlobalNames::WorkerDebuggerGlobalScope |
2946
4
                GlobalNames::WorkletGlobalScope |
2947
4
                GlobalNames::AudioWorkletGlobalScope)) == 0,
2948
4
             "Unknown non-exposed global type");
2949
4
2950
4
  const char* name = js::GetObjectClass(aGlobal)->name;
2951
4
2952
4
  if ((aNonExposedGlobals & GlobalNames::Window) &&
2953
4
      !strcmp(name, "Window")) {
2954
0
    return true;
2955
0
  }
2956
4
2957
4
  if ((aNonExposedGlobals & GlobalNames::BackstagePass) &&
2958
4
      !strcmp(name, "BackstagePass")) {
2959
0
    return true;
2960
0
  }
2961
4
2962
4
  if ((aNonExposedGlobals & GlobalNames::DedicatedWorkerGlobalScope) &&
2963
4
      !strcmp(name, "DedicatedWorkerGlobalScope")) {
2964
0
    return true;
2965
0
  }
2966
4
2967
4
  if ((aNonExposedGlobals & GlobalNames::SharedWorkerGlobalScope) &&
2968
4
      !strcmp(name, "SharedWorkerGlobalScope")) {
2969
0
    return true;
2970
0
  }
2971
4
2972
4
  if ((aNonExposedGlobals & GlobalNames::ServiceWorkerGlobalScope) &&
2973
4
      !strcmp(name, "ServiceWorkerGlobalScope")) {
2974
0
    return true;
2975
0
  }
2976
4
2977
4
  if ((aNonExposedGlobals & GlobalNames::WorkerDebuggerGlobalScope) &&
2978
4
      !strcmp(name, "WorkerDebuggerGlobalScopex")) {
2979
0
    return true;
2980
0
  }
2981
4
2982
4
  if ((aNonExposedGlobals & GlobalNames::WorkletGlobalScope) &&
2983
4
      !strcmp(name, "WorkletGlobalScope")) {
2984
0
    return true;
2985
0
  }
2986
4
2987
4
  if ((aNonExposedGlobals & GlobalNames::AudioWorkletGlobalScope) &&
2988
4
      !strcmp(name, "AudioWorkletGlobalScope")) {
2989
0
    return true;
2990
0
  }
2991
4
2992
4
  return false;
2993
4
}
2994
2995
namespace binding_detail {
2996
2997
/**
2998
 * A ThisPolicy struct needs to provide the following methods:
2999
 *
3000
 * HasValidThisValue: Takes a CallArgs and returns a boolean indicating whether
3001
 *                    the thisv() is valid in the sense of being the right type
3002
 *                    of Value.  It does not check whether it's the right sort
3003
 *                    of object if the Value is a JSObject*.
3004
 *
3005
 * ExtractThisObject: Takes a CallArgs for which HasValidThisValue was true and
3006
 *                    returns the JSObject* to use for getting |this|.
3007
 *
3008
 * MaybeUnwrapThisObject: If our |this| is a JSObject* that this policy wants to
3009
 *                        allow unchecked access to for this
3010
 *                        getter/setter/method, unwrap it.  Otherwise just
3011
 *                        return the given object.
3012
 *
3013
 * HandleInvalidThis: If the |this| is not valid (wrong type of value, wrong
3014
 *                    object, etc), decide what to do about it.  Returns a
3015
 *                    boolean to return from the JSNative (false for failure,
3016
 *                    true for succcess).
3017
 */
3018
struct NormalThisPolicy
3019
{
3020
  // This needs to be inlined because it's called on no-exceptions fast-paths.
3021
  static MOZ_ALWAYS_INLINE bool HasValidThisValue(const JS::CallArgs& aArgs)
3022
0
  {
3023
0
    // Per WebIDL spec, all getters/setters/methods allow null/undefined "this"
3024
0
    // and coerce it to the global.  Then the "is this the right interface?"
3025
0
    // check fails if the interface involved is not one that the global
3026
0
    // implements.
3027
0
    //
3028
0
    // As an optimization, we skip doing the null/undefined stuff if we know our
3029
0
    // interface is not implemented by the global.
3030
0
    return aArgs.thisv().isObject();
3031
0
  }
3032
3033
  static MOZ_ALWAYS_INLINE JSObject* ExtractThisObject(const JS::CallArgs& aArgs)
3034
0
  {
3035
0
    return &aArgs.thisv().toObject();
3036
0
  }
3037
3038
  static MOZ_ALWAYS_INLINE JSObject* MaybeUnwrapThisObject(JSObject* aObj)
3039
0
  {
3040
0
    return aObj;
3041
0
  }
3042
3043
  static bool HandleInvalidThis(JSContext* aCx, JS::CallArgs& aArgs,
3044
                                bool aSecurityError,
3045
                                prototypes::ID aProtoId)
3046
0
  {
3047
0
    return ThrowInvalidThis(aCx, aArgs, aSecurityError, aProtoId);
3048
0
  }
3049
};
3050
3051
struct MaybeGlobalThisPolicy : public NormalThisPolicy
3052
{
3053
  static MOZ_ALWAYS_INLINE bool HasValidThisValue(const JS::CallArgs& aArgs)
3054
0
  {
3055
0
    // Here we have to allow null/undefined.
3056
0
    return aArgs.thisv().isObject() || aArgs.thisv().isNullOrUndefined();
3057
0
  }
3058
3059
  static MOZ_ALWAYS_INLINE JSObject* ExtractThisObject(const JS::CallArgs& aArgs)
3060
0
  {
3061
0
    return aArgs.thisv().isObject() ?
3062
0
      &aArgs.thisv().toObject() :
3063
0
      JS::GetNonCCWObjectGlobal(&aArgs.callee());
3064
0
  }
3065
3066
  // We want the MaybeUnwrapThisObject of NormalThisPolicy.
3067
3068
  // We want the HandleInvalidThis of NormalThisPolicy.
3069
};
3070
3071
// There are some LenientThis things on globals, so we inherit from
3072
// MaybeGlobalThisPolicy.
3073
struct LenientThisPolicy : public MaybeGlobalThisPolicy
3074
{
3075
  // We want the HasValidThisValue of MaybeGlobalThisPolicy.
3076
3077
  // We want the ExtractThisObject of MaybeGlobalThisPolicy.
3078
3079
  // We want the MaybeUnwrapThisObject of MaybeGlobalThisPolicy.
3080
3081
  static bool HandleInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
3082
                                bool aSecurityError,
3083
                                prototypes::ID aProtoId)
3084
0
  {
3085
0
    MOZ_ASSERT(!JS_IsExceptionPending(aCx));
3086
0
    if (!ReportLenientThisUnwrappingFailure(aCx, &aArgs.callee())) {
3087
0
      return false;
3088
0
    }
3089
0
    aArgs.rval().set(JS::UndefinedValue());
3090
0
    return true;
3091
0
  }
3092
};
3093
3094
// There are some cross-origin things on globals, so we inherit from
3095
// MaybeGlobalThisPolicy.
3096
struct CrossOriginThisPolicy : public MaybeGlobalThisPolicy
3097
{
3098
  // We want the HasValidThisValue of MaybeGlobalThisPolicy.
3099
3100
  // We want the ExtractThisObject of MaybeGlobalThisPolicy.
3101
3102
  static MOZ_ALWAYS_INLINE JSObject* MaybeUnwrapThisObject(JSObject* aObj)
3103
0
  {
3104
0
    if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
3105
0
      return js::UncheckedUnwrap(aObj);
3106
0
    }
3107
0
3108
0
    // Else just return aObj; our UnwrapObjectInternal call will try to
3109
0
    // CheckedUnwrap it, and eitehr succeed or get a security error as needed.
3110
0
    return aObj;
3111
0
  }
3112
3113
  // We want the HandleInvalidThis of MaybeGlobalThisPolicy.
3114
};
3115
3116
/**
3117
 * An ExceptionPolicy struct provides a single HandleException method which is
3118
 * used to handle an exception, if any.  The method is given the current
3119
 * success/failure boolean so it can decide whether there is in fact an
3120
 * exception involved.
3121
 */
3122
struct ThrowExceptions
3123
{
3124
  // This needs to be inlined because it's called even on no-exceptions
3125
  // fast-paths.
3126
  static MOZ_ALWAYS_INLINE bool HandleException(JSContext* aCx,
3127
                                                JS::CallArgs& aArgs,
3128
                                                const JSJitInfo* aInfo,
3129
                                                bool aOK)
3130
0
  {
3131
0
    return aOK;
3132
0
  }
3133
};
3134
3135
struct ConvertExceptionsToPromises
3136
{
3137
  // This needs to be inlined because it's called even on no-exceptions
3138
  // fast-paths.
3139
  static MOZ_ALWAYS_INLINE bool HandleException(JSContext* aCx,
3140
                                                JS::CallArgs& aArgs,
3141
                                                const JSJitInfo* aInfo,
3142
                                                bool aOK)
3143
0
  {
3144
0
    // Promise-returning getters/methods always return objects.
3145
0
    MOZ_ASSERT(aInfo->returnType() == JSVAL_TYPE_OBJECT);
3146
0
3147
0
    if (aOK) {
3148
0
      return true;
3149
0
    }
3150
0
3151
0
    return ConvertExceptionToPromise(aCx, aArgs.rval());
3152
0
  }
3153
};
3154
3155
template<typename ThisPolicy, typename ExceptionPolicy>
3156
bool
3157
GenericGetter(JSContext* cx, unsigned argc, JS::Value* vp)
3158
0
{
3159
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
3160
0
  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
3161
0
  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
3162
0
  if (!ThisPolicy::HasValidThisValue(args)) {
3163
0
    bool ok = ThisPolicy::HandleInvalidThis(cx, args, false, protoID);
3164
0
    return ExceptionPolicy::HandleException(cx, args, info, ok);
3165
0
  }
3166
0
  JS::Rooted<JSObject*> obj(cx, ThisPolicy::ExtractThisObject(args));
3167
0
3168
0
  // NOTE: we want to leave obj in its initial compartment, so don't want to
3169
0
  // pass it to UnwrapObjectInternal.  Also, the thing we pass to
3170
0
  // UnwrapObjectInternal may be affected by our ThisPolicy.
3171
0
  JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
3172
0
  void* self;
3173
0
  {
3174
0
    binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
3175
0
    nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
3176
0
                                                                   self,
3177
0
                                                                   protoID,
3178
0
                                                                   info->depth);
3179
0
    if (NS_FAILED(rv)) {
3180
0
      bool ok =
3181
0
        ThisPolicy::HandleInvalidThis(cx, args,
3182
0
                                      rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
3183
0
                                      protoID);
3184
0
      return ExceptionPolicy::HandleException(cx, args, info, ok);
3185
0
    }
3186
0
  }
3187
0
3188
0
  MOZ_ASSERT(info->type() == JSJitInfo::Getter);
3189
0
  JSJitGetterOp getter = info->getter;
3190
0
  bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
3191
#ifdef DEBUG
3192
  if (ok) {
3193
    AssertReturnTypeMatchesJitinfo(info, args.rval());
3194
  }
3195
#endif
3196
  return ExceptionPolicy::HandleException(cx, args, info, ok);
3197
0
}
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericGetter<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericGetter<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ConvertExceptionsToPromises>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericGetter<mozilla::dom::binding_detail::MaybeGlobalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericGetter<mozilla::dom::binding_detail::MaybeGlobalThisPolicy, mozilla::dom::binding_detail::ConvertExceptionsToPromises>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericGetter<mozilla::dom::binding_detail::LenientThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericGetter<mozilla::dom::binding_detail::CrossOriginThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
3198
3199
// Force instantiation of the specializations of GenericGetter we need here.
3200
template bool
3201
GenericGetter<NormalThisPolicy, ThrowExceptions>(
3202
  JSContext* cx, unsigned argc, JS::Value* vp);
3203
template bool
3204
GenericGetter<NormalThisPolicy, ConvertExceptionsToPromises>(
3205
  JSContext* cx, unsigned argc, JS::Value* vp);
3206
template bool
3207
GenericGetter<MaybeGlobalThisPolicy, ThrowExceptions>(
3208
  JSContext* cx, unsigned argc, JS::Value* vp);
3209
template bool
3210
GenericGetter<MaybeGlobalThisPolicy, ConvertExceptionsToPromises>(
3211
  JSContext* cx, unsigned argc, JS::Value* vp);
3212
template bool
3213
GenericGetter<LenientThisPolicy, ThrowExceptions>(
3214
  JSContext* cx, unsigned argc, JS::Value* vp);
3215
// There aren't any [LenientThis] Promise-returning getters, so don't
3216
// bother instantiating that specialization.
3217
template bool
3218
GenericGetter<CrossOriginThisPolicy, ThrowExceptions>(
3219
  JSContext* cx, unsigned argc, JS::Value* vp);
3220
// There aren't any cross-origin Promise-returning getters, so don't
3221
// bother instantiating that specialization.
3222
3223
template<typename ThisPolicy>
3224
bool
3225
GenericSetter(JSContext* cx, unsigned argc, JS::Value* vp)
3226
0
{
3227
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
3228
0
  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
3229
0
  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
3230
0
  if (!ThisPolicy::HasValidThisValue(args)) {
3231
0
    return ThisPolicy::HandleInvalidThis(cx, args, false, protoID);
3232
0
  }
3233
0
  JS::Rooted<JSObject*> obj(cx, ThisPolicy::ExtractThisObject(args));
3234
0
3235
0
  // NOTE: we want to leave obj in its initial compartment, so don't want to
3236
0
  // pass it to UnwrapObject.  Also the thing we pass to UnwrapObjectInternal
3237
0
  // may be affected by our ThisPolicy.
3238
0
  JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
3239
0
  void* self;
3240
0
  {
3241
0
    binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
3242
0
    nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
3243
0
                                                                   self,
3244
0
                                                                   protoID,
3245
0
                                                                   info->depth);
3246
0
    if (NS_FAILED(rv)) {
3247
0
      return
3248
0
        ThisPolicy::HandleInvalidThis(cx, args,
3249
0
                                      rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
3250
0
                                      protoID);
3251
0
    }
3252
0
  }
3253
0
  if (args.length() == 0) {
3254
0
    return ThrowNoSetterArg(cx, protoID);
3255
0
  }
3256
0
  MOZ_ASSERT(info->type() == JSJitInfo::Setter);
3257
0
  JSJitSetterOp setter = info->setter;
3258
0
  if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
3259
0
    return false;
3260
0
  }
3261
0
  args.rval().setUndefined();
3262
#ifdef DEBUG
3263
  AssertReturnTypeMatchesJitinfo(info, args.rval());
3264
#endif
3265
  return true;
3266
0
}
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericSetter<mozilla::dom::binding_detail::NormalThisPolicy>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericSetter<mozilla::dom::binding_detail::MaybeGlobalThisPolicy>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericSetter<mozilla::dom::binding_detail::LenientThisPolicy>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericSetter<mozilla::dom::binding_detail::CrossOriginThisPolicy>(JSContext*, unsigned int, JS::Value*)
3267
3268
// Force instantiation of the specializations of GenericSetter we need here.
3269
template bool
3270
GenericSetter<NormalThisPolicy>(JSContext* cx, unsigned argc, JS::Value* vp);
3271
template bool
3272
GenericSetter<MaybeGlobalThisPolicy>(JSContext* cx, unsigned argc,
3273
                                     JS::Value* vp);
3274
template bool
3275
GenericSetter<LenientThisPolicy>(JSContext* cx, unsigned argc, JS::Value* vp);
3276
template bool
3277
GenericSetter<CrossOriginThisPolicy>(JSContext* cx, unsigned argc,
3278
                                     JS::Value* vp);
3279
3280
template<typename ThisPolicy, typename ExceptionPolicy>
3281
bool
3282
GenericMethod(JSContext* cx, unsigned argc, JS::Value* vp)
3283
0
{
3284
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
3285
0
  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
3286
0
  prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
3287
0
  if (!ThisPolicy::HasValidThisValue(args)) {
3288
0
    bool ok = ThisPolicy::HandleInvalidThis(cx, args, false, protoID);
3289
0
    return ExceptionPolicy::HandleException(cx, args, info, ok);
3290
0
  }
3291
0
  JS::Rooted<JSObject*> obj(cx, ThisPolicy::ExtractThisObject(args));
3292
0
3293
0
  // NOTE: we want to leave obj in its initial compartment, so don't want to
3294
0
  // pass it to UnwrapObjectInternal.  Also, the thing we pass to
3295
0
  // UnwrapObjectInternal may be affected by our ThisPolicy.
3296
0
  JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
3297
0
  void* self;
3298
0
  {
3299
0
    binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
3300
0
    nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
3301
0
                                                                   self,
3302
0
                                                                   protoID,
3303
0
                                                                   info->depth);
3304
0
    if (NS_FAILED(rv)) {
3305
0
      bool ok =
3306
0
        ThisPolicy::HandleInvalidThis(cx, args,
3307
0
                                      rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
3308
0
                                      protoID);
3309
0
      return ExceptionPolicy::HandleException(cx, args, info, ok);
3310
0
    }
3311
0
  }
3312
0
  MOZ_ASSERT(info->type() == JSJitInfo::Method);
3313
0
  JSJitMethodOp method = info->method;
3314
0
  bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
3315
#ifdef DEBUG
3316
  if (ok) {
3317
    AssertReturnTypeMatchesJitinfo(info, args.rval());
3318
  }
3319
#endif
3320
  return ExceptionPolicy::HandleException(cx, args, info, ok);
3321
0
}
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ConvertExceptionsToPromises>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::MaybeGlobalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::MaybeGlobalThisPolicy, mozilla::dom::binding_detail::ConvertExceptionsToPromises>(JSContext*, unsigned int, JS::Value*)
Unexecuted instantiation: bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::CrossOriginThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*)
3322
3323
// Force instantiation of the specializations of GenericMethod we need here.
3324
template bool
3325
GenericMethod<NormalThisPolicy, ThrowExceptions>(
3326
  JSContext* cx, unsigned argc, JS::Value* vp);
3327
template bool
3328
GenericMethod<NormalThisPolicy, ConvertExceptionsToPromises>(
3329
  JSContext* cx, unsigned argc, JS::Value* vp);
3330
template bool
3331
GenericMethod<MaybeGlobalThisPolicy, ThrowExceptions>(
3332
  JSContext* cx, unsigned argc, JS::Value* vp);
3333
template bool
3334
GenericMethod<MaybeGlobalThisPolicy, ConvertExceptionsToPromises>(
3335
  JSContext* cx, unsigned argc, JS::Value* vp);
3336
template bool
3337
GenericMethod<CrossOriginThisPolicy, ThrowExceptions>(
3338
  JSContext* cx, unsigned argc, JS::Value* vp);
3339
// There aren't any cross-origin Promise-returning methods, so don't
3340
// bother instantiating that specialization.
3341
3342
} // namespace binding_detail
3343
3344
bool
3345
StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp)
3346
0
{
3347
0
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
3348
0
3349
0
  const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
3350
0
  MOZ_ASSERT(info);
3351
0
  MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod);
3352
0
3353
0
  bool ok = info->staticMethod(cx, argc, vp);
3354
0
  if (ok) {
3355
0
    return true;
3356
0
  }
3357
0
3358
0
  return ConvertExceptionToPromise(cx, args.rval());
3359
0
}
3360
3361
bool
3362
ConvertExceptionToPromise(JSContext* cx,
3363
                          JS::MutableHandle<JS::Value> rval)
3364
0
{
3365
0
  JS::Rooted<JS::Value> exn(cx);
3366
0
  if (!JS_GetPendingException(cx, &exn)) {
3367
0
    // This is very important: if there is no pending exception here but we're
3368
0
    // ending up in this code, that means the callee threw an uncatchable
3369
0
    // exception.  Just propagate that out as-is.
3370
0
    return false;
3371
0
  }
3372
0
3373
0
  JS_ClearPendingException(cx);
3374
0
3375
0
  JSObject* promise = JS::CallOriginalPromiseReject(cx, exn);
3376
0
  if (!promise) {
3377
0
    // We just give up.  Put the exception back.
3378
0
    JS_SetPendingException(cx, exn);
3379
0
    return false;
3380
0
  }
3381
0
3382
0
  rval.setObject(*promise);
3383
0
  return true;
3384
0
}
3385
3386
/* static */
3387
void
3388
CreateGlobalOptionsWithXPConnect::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
3389
0
{
3390
0
  xpc::TraceXPCGlobal(aTrc, aObj);
3391
0
}
3392
3393
/* static */
3394
bool
3395
CreateGlobalOptionsWithXPConnect::PostCreateGlobal(JSContext* aCx,
3396
                                                   JS::Handle<JSObject*> aGlobal)
3397
0
{
3398
0
  JSPrincipals* principals =
3399
0
    JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(aGlobal));
3400
0
  nsIPrincipal* principal = nsJSPrincipals::get(principals);
3401
0
3402
0
  // We create the SiteIdentifier here instead of in the XPCWrappedNativeScope
3403
0
  // constructor because this is fallible.
3404
0
  SiteIdentifier site;
3405
0
  nsresult rv = BasePrincipal::Cast(principal)->GetSiteIdentifier(site);
3406
0
  NS_ENSURE_SUCCESS(rv, false);
3407
0
3408
0
  // Invoking the XPCWrappedNativeScope constructor automatically hooks it
3409
0
  // up to the realm of aGlobal.
3410
0
  (void) new XPCWrappedNativeScope(aCx, aGlobal, site);
3411
0
  return true;
3412
0
}
3413
3414
static bool sRegisteredDOMNames = false;
3415
3416
static void
3417
RegisterDOMNames()
3418
0
{
3419
0
  if (sRegisteredDOMNames) {
3420
0
    return;
3421
0
  }
3422
0
3423
0
  // Register new DOM bindings
3424
0
  WebIDLGlobalNameHash::Init();
3425
0
3426
0
  sRegisteredDOMNames = true;
3427
0
}
3428
3429
/* static */
3430
bool
3431
CreateGlobalOptions<nsGlobalWindowInner>::PostCreateGlobal(JSContext* aCx,
3432
                                                           JS::Handle<JSObject*> aGlobal)
3433
0
{
3434
0
  RegisterDOMNames();
3435
0
3436
0
  return CreateGlobalOptionsWithXPConnect::PostCreateGlobal(aCx, aGlobal);
3437
0
}
3438
3439
#ifdef DEBUG
3440
void
3441
AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
3442
                               JS::Handle<JS::Value> aValue)
3443
{
3444
  switch (aJitInfo->returnType()) {
3445
  case JSVAL_TYPE_UNKNOWN:
3446
    // Any value is good.
3447
    break;
3448
  case JSVAL_TYPE_DOUBLE:
3449
    // The value could actually be an int32 value as well.
3450
    MOZ_ASSERT(aValue.isNumber());
3451
    break;
3452
  case JSVAL_TYPE_INT32:
3453
    MOZ_ASSERT(aValue.isInt32());
3454
    break;
3455
  case JSVAL_TYPE_UNDEFINED:
3456
    MOZ_ASSERT(aValue.isUndefined());
3457
    break;
3458
  case JSVAL_TYPE_BOOLEAN:
3459
    MOZ_ASSERT(aValue.isBoolean());
3460
    break;
3461
  case JSVAL_TYPE_STRING:
3462
    MOZ_ASSERT(aValue.isString());
3463
    break;
3464
  case JSVAL_TYPE_NULL:
3465
    MOZ_ASSERT(aValue.isNull());
3466
    break;
3467
  case JSVAL_TYPE_OBJECT:
3468
    MOZ_ASSERT(aValue.isObject());
3469
    break;
3470
  default:
3471
    // Someone messed up their jitinfo type.
3472
    MOZ_ASSERT(false, "Unexpected JSValueType stored in jitinfo");
3473
    break;
3474
  }
3475
}
3476
#endif
3477
3478
bool
3479
CallerSubsumes(JSObject *aObject)
3480
0
{
3481
0
  nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
3482
0
  return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
3483
0
}
3484
3485
nsresult
3486
UnwrapArgImpl(JSContext* cx,
3487
              JS::Handle<JSObject*> src,
3488
              const nsIID &iid,
3489
              void **ppArg)
3490
5
{
3491
5
  if (!NS_IsMainThread()) {
3492
0
    return NS_ERROR_NOT_AVAILABLE;
3493
0
  }
3494
5
3495
5
  nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(src);
3496
5
  if (iface) {
3497
5
    if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
3498
0
      return NS_ERROR_XPC_BAD_CONVERT_JS;
3499
0
    }
3500
5
3501
5
    return NS_OK;
3502
5
  }
3503
0
3504
0
  // Only allow XPCWrappedJS stuff in system code.  Ideally we would remove this
3505
0
  // even there, but that involves converting some things to WebIDL callback
3506
0
  // interfaces and making some other things builtinclass...
3507
0
  if (!nsContentUtils::IsSystemCaller(cx)) {
3508
0
    return NS_ERROR_XPC_BAD_CONVERT_JS;
3509
0
  }
3510
0
3511
0
  RefPtr<nsXPCWrappedJS> wrappedJS;
3512
0
  nsresult rv =
3513
0
    nsXPCWrappedJS::GetNewOrUsed(cx, src, iid, getter_AddRefs(wrappedJS));
3514
0
  if (NS_FAILED(rv) || !wrappedJS) {
3515
0
    return rv;
3516
0
  }
3517
0
3518
0
  // We need to go through the QueryInterface logic to make this return
3519
0
  // the right thing for the various 'special' interfaces; e.g.
3520
0
  // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
3521
0
  // there is an outer to avoid nasty recursion.
3522
0
  return wrappedJS->QueryInterface(iid, ppArg);
3523
0
}
3524
3525
nsresult
3526
UnwrapWindowProxyImpl(JSContext* cx,
3527
                      JS::Handle<JSObject*> src,
3528
                      nsPIDOMWindowOuter** ppArg)
3529
0
{
3530
0
  nsCOMPtr<nsPIDOMWindowInner> inner;
3531
0
  nsresult rv = UnwrapArg<nsPIDOMWindowInner>(cx, src, getter_AddRefs(inner));
3532
0
  NS_ENSURE_SUCCESS(rv, rv);
3533
0
3534
0
  nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
3535
0
  outer.forget(ppArg);
3536
0
  return NS_OK;
3537
0
}
3538
3539
bool
3540
SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
3541
                    JS::Handle<jsid> id, bool* resolvedp)
3542
50
{
3543
50
  if (!ResolveGlobal(cx, obj, id, resolvedp)) {
3544
0
    return false;
3545
0
  }
3546
50
3547
50
  if (*resolvedp) {
3548
1
    return true;
3549
1
  }
3550
49
3551
49
  return ResolveSystemBinding(cx, obj, id, resolvedp);
3552
49
}
3553
3554
bool
3555
SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
3556
0
{
3557
0
  bool ignored = false;
3558
0
  return JS_EnumerateStandardClasses(cx, obj) &&
3559
0
         ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
3560
0
}
3561
3562
template<decltype(JS::NewMapObject) Method>
3563
bool
3564
GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
3565
                               size_t aSlotIndex,
3566
                               JS::MutableHandle<JSObject*> aBackingObj,
3567
                               bool* aBackingObjCreated)
3568
0
{
3569
0
  JS::Rooted<JSObject*> reflector(aCx);
3570
0
  reflector = IsDOMObject(aObj) ? aObj : js::UncheckedUnwrap(aObj,
3571
0
                                                             /* stopAtWindowProxy = */ false);
3572
0
3573
0
  // Retrieve the backing object from the reserved slot on the maplike/setlike
3574
0
  // object. If it doesn't exist yet, create it.
3575
0
  JS::Rooted<JS::Value> slotValue(aCx);
3576
0
  slotValue = js::GetReservedSlot(reflector, aSlotIndex);
3577
0
  if (slotValue.isUndefined()) {
3578
0
    // Since backing object access can happen in non-originating realms,
3579
0
    // make sure to create the backing object in reflector realm.
3580
0
    {
3581
0
      JSAutoRealm ar(aCx, reflector);
3582
0
      JS::Rooted<JSObject*> newBackingObj(aCx);
3583
0
      newBackingObj.set(Method(aCx));
3584
0
      if (NS_WARN_IF(!newBackingObj)) {
3585
0
        return false;
3586
0
      }
3587
0
      js::SetReservedSlot(reflector, aSlotIndex, JS::ObjectValue(*newBackingObj));
3588
0
    }
3589
0
    slotValue = js::GetReservedSlot(reflector, aSlotIndex);
3590
0
    *aBackingObjCreated = true;
3591
0
  } else {
3592
0
    *aBackingObjCreated = false;
3593
0
  }
3594
0
  if (!MaybeWrapNonDOMObjectValue(aCx, &slotValue)) {
3595
0
    return false;
3596
0
  }
3597
0
  aBackingObj.set(&slotValue.toObject());
3598
0
  return true;
3599
0
}
Unexecuted instantiation: bool mozilla::dom::GetMaplikeSetlikeBackingObject<&JS::NewMapObject>(JSContext*, JS::Handle<JSObject*>, unsigned long, JS::MutableHandle<JSObject*>, bool*)
Unexecuted instantiation: bool mozilla::dom::GetMaplikeSetlikeBackingObject<&JS::NewSetObject>(JSContext*, JS::Handle<JSObject*>, unsigned long, JS::MutableHandle<JSObject*>, bool*)
3600
3601
bool
3602
GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
3603
                        size_t aSlotIndex,
3604
                        JS::MutableHandle<JSObject*> aBackingObj,
3605
                        bool* aBackingObjCreated)
3606
0
{
3607
0
  return GetMaplikeSetlikeBackingObject<JS::NewMapObject>(aCx, aObj, aSlotIndex,
3608
0
                                                          aBackingObj,
3609
0
                                                          aBackingObjCreated);
3610
0
}
3611
3612
bool
3613
GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
3614
                        size_t aSlotIndex,
3615
                        JS::MutableHandle<JSObject*> aBackingObj,
3616
                        bool* aBackingObjCreated)
3617
0
{
3618
0
  return GetMaplikeSetlikeBackingObject<JS::NewSetObject>(aCx, aObj, aSlotIndex,
3619
0
                                                          aBackingObj,
3620
0
                                                          aBackingObjCreated);
3621
0
}
3622
3623
bool
3624
ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
3625
0
{
3626
0
  JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
3627
0
  // Unpack callback and object from slots
3628
0
  JS::Rooted<JS::Value>
3629
0
    callbackFn(aCx, js::GetFunctionNativeReserved(&args.callee(),
3630
0
                                                  FOREACH_CALLBACK_SLOT));
3631
0
  JS::Rooted<JS::Value>
3632
0
    maplikeOrSetlikeObj(aCx,
3633
0
                        js::GetFunctionNativeReserved(&args.callee(),
3634
0
                                                      FOREACH_MAPLIKEORSETLIKEOBJ_SLOT));
3635
0
  MOZ_ASSERT(aArgc == 3);
3636
0
  JS::AutoValueVector newArgs(aCx);
3637
0
  // Arguments are passed in as value, key, object. Keep value and key, replace
3638
0
  // object with the maplike/setlike object.
3639
0
  if (!newArgs.append(args.get(0))) {
3640
0
    return false;
3641
0
  }
3642
0
  if (!newArgs.append(args.get(1))) {
3643
0
    return false;
3644
0
  }
3645
0
  if (!newArgs.append(maplikeOrSetlikeObj)) {
3646
0
    return false;
3647
0
  }
3648
0
  JS::Rooted<JS::Value> rval(aCx, JS::UndefinedValue());
3649
0
  // Now actually call the user specified callback
3650
0
  return JS::Call(aCx, args.thisv(), callbackFn, newArgs, &rval);
3651
0
}
3652
3653
static inline prototypes::ID
3654
GetProtoIdForNewtarget(JS::Handle<JSObject*> aNewTarget)
3655
0
{
3656
0
  const js::Class* newTargetClass = js::GetObjectClass(aNewTarget);
3657
0
  if (IsDOMIfaceAndProtoClass(newTargetClass)) {
3658
0
    const DOMIfaceAndProtoJSClass* newTargetIfaceClass =
3659
0
      DOMIfaceAndProtoJSClass::FromJSClass(newTargetClass);
3660
0
    if (newTargetIfaceClass->mType == eInterface) {
3661
0
      return newTargetIfaceClass->mPrototypeID;
3662
0
    }
3663
0
  } else if (JS_IsNativeFunction(aNewTarget, Constructor)) {
3664
0
    return GetNativePropertyHooksFromConstructorFunction(aNewTarget)->mPrototypeID;
3665
0
  }
3666
0
3667
0
  return prototypes::id::_ID_Count;
3668
0
}
3669
3670
bool
3671
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
3672
                JS::MutableHandle<JSObject*> aDesiredProto)
3673
0
{
3674
0
  if (!aCallArgs.isConstructing()) {
3675
0
    aDesiredProto.set(nullptr);
3676
0
    return true;
3677
0
  }
3678
0
3679
0
  // The desired prototype depends on the actual constructor that was invoked,
3680
0
  // which is passed to us as the newTarget in the callargs.  We want to do
3681
0
  // something akin to the ES6 specification's GetProtototypeFromConstructor (so
3682
0
  // get .prototype on the newTarget, with a fallback to some sort of default).
3683
0
3684
0
  // First, a fast path for the case when the the constructor is in fact one of
3685
0
  // our DOM constructors.  This is safe because on those the "constructor"
3686
0
  // property is non-configurable and non-writable, so we don't have to do the
3687
0
  // slow JS_GetProperty call.
3688
0
  JS::Rooted<JSObject*> newTarget(aCx, &aCallArgs.newTarget().toObject());
3689
0
  JS::Rooted<JSObject*> originalNewTarget(aCx, newTarget);
3690
0
  // See whether we have a known DOM constructor here, such that we can take a
3691
0
  // fast path.
3692
0
  prototypes::ID protoID = GetProtoIdForNewtarget(newTarget);
3693
0
  if (protoID == prototypes::id::_ID_Count) {
3694
0
    // We might still have a cross-compartment wrapper for a known DOM
3695
0
    // constructor.
3696
0
    newTarget = js::CheckedUnwrap(newTarget);
3697
0
    if (newTarget && newTarget != originalNewTarget) {
3698
0
      protoID = GetProtoIdForNewtarget(newTarget);
3699
0
    }
3700
0
  }
3701
0
3702
0
  if (protoID != prototypes::id::_ID_Count) {
3703
0
    ProtoAndIfaceCache& protoAndIfaceCache =
3704
0
      *GetProtoAndIfaceCache(JS::GetNonCCWObjectGlobal(newTarget));
3705
0
    aDesiredProto.set(protoAndIfaceCache.EntrySlotMustExist(protoID));
3706
0
    if (newTarget != originalNewTarget) {
3707
0
      return JS_WrapObject(aCx, aDesiredProto);
3708
0
    }
3709
0
    return true;
3710
0
  }
3711
0
3712
0
  // Slow path.  This basically duplicates the ES6 spec's
3713
0
  // GetPrototypeFromConstructor except that instead of taking a string naming
3714
0
  // the fallback prototype we just fall back to using null and assume that our
3715
0
  // caller will then pick the right default.  The actual defaulting behavior
3716
0
  // here still needs to be defined in the Web IDL specification.
3717
0
  //
3718
0
  // Note that it's very important to do this property get on originalNewTarget,
3719
0
  // not our unwrapped newTarget, since we want to get Xray behavior here as
3720
0
  // needed.
3721
0
  // XXXbz for speed purposes, using a preinterned id here sure would be nice.
3722
0
  JS::Rooted<JS::Value> protoVal(aCx);
3723
0
  if (!JS_GetProperty(aCx, originalNewTarget, "prototype", &protoVal)) {
3724
0
    return false;
3725
0
  }
3726
0
3727
0
  if (!protoVal.isObject()) {
3728
0
    aDesiredProto.set(nullptr);
3729
0
    return true;
3730
0
  }
3731
0
3732
0
  aDesiredProto.set(&protoVal.toObject());
3733
0
  return true;
3734
0
}
3735
3736
namespace {
3737
3738
class MOZ_RAII AutoConstructionDepth final
3739
{
3740
public:
3741
  MOZ_IMPLICIT AutoConstructionDepth(CustomElementDefinition* aDefinition)
3742
    : mDefinition(aDefinition)
3743
0
  {
3744
0
    MOZ_ASSERT(mDefinition->mConstructionStack.IsEmpty());
3745
0
3746
0
    mDefinition->mConstructionDepth++;
3747
0
    // If the mConstructionDepth isn't matched with the length of mPrefixStack,
3748
0
    // this means the constructor is called directly from JS, i.e.
3749
0
    // 'new CustomElementConstructor()', we have to push a dummy prefix into
3750
0
    // stack.
3751
0
    if (mDefinition->mConstructionDepth > mDefinition->mPrefixStack.Length()) {
3752
0
      mDidPush = true;
3753
0
      mDefinition->mPrefixStack.AppendElement(nullptr);
3754
0
    }
3755
0
3756
0
    MOZ_ASSERT(mDefinition->mConstructionDepth == mDefinition->mPrefixStack.Length());
3757
0
  }
3758
3759
  ~AutoConstructionDepth()
3760
0
  {
3761
0
    MOZ_ASSERT(mDefinition->mConstructionDepth > 0);
3762
0
    MOZ_ASSERT(mDefinition->mConstructionDepth == mDefinition->mPrefixStack.Length());
3763
0
3764
0
    if (mDidPush) {
3765
0
      MOZ_ASSERT(mDefinition->mPrefixStack.LastElement() == nullptr);
3766
0
      mDefinition->mPrefixStack.RemoveLastElement();
3767
0
    }
3768
0
    mDefinition->mConstructionDepth--;
3769
0
  }
3770
3771
private:
3772
  CustomElementDefinition* mDefinition;
3773
  bool mDidPush = false;
3774
};
3775
3776
} // anonymous namespace
3777
3778
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
3779
namespace binding_detail {
3780
bool
3781
HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
3782
                constructors::id::ID aConstructorId,
3783
                prototypes::id::ID aProtoId,
3784
                CreateInterfaceObjectsMethod aCreator)
3785
0
{
3786
0
  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
3787
0
3788
0
  // Per spec, this is technically part of step 3, but doing the check
3789
0
  // directly lets us provide a better error message.  And then in
3790
0
  // step 2 we can work with newTarget in a simpler way because we
3791
0
  // know it's an object.
3792
0
  if (!args.isConstructing()) {
3793
0
    return ThrowConstructorWithoutNew(aCx,
3794
0
                                      NamesOfInterfacesWithProtos(aProtoId));
3795
0
  }
3796
0
3797
0
  JS::Rooted<JSObject*> callee(aCx, &args.callee());
3798
0
  // 'callee' is not a function here; it's either an Xray for our interface
3799
0
  // object or the interface object itself.  So caling XrayAwareCalleeGlobal on
3800
0
  // it is not safe.  But since in the Xray case it's a wrapper for our
3801
0
  // interface object, we can just construct our GlobalObject from it and end
3802
0
  // up with the right thing.
3803
0
  GlobalObject global(aCx, callee);
3804
0
  if (global.Failed()) {
3805
0
    return false;
3806
0
  }
3807
0
3808
0
  // Now we start the [HTMLConstructor] algorithm steps from
3809
0
  // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
3810
0
3811
0
  // Step 1.
3812
0
  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
3813
0
  if (!window) {
3814
0
    // This means we ended up with an HTML Element interface object defined in
3815
0
    // a non-Window scope.  That's ... pretty unexpected.
3816
0
    return Throw(aCx, NS_ERROR_UNEXPECTED);
3817
0
  }
3818
0
  RefPtr<mozilla::dom::CustomElementRegistry> registry(window->CustomElements());
3819
0
3820
0
  // Technically, per spec, a window always has a document.  In Gecko, a
3821
0
  // sufficiently torn-down window might not, so check for that case.  We're
3822
0
  // going to need a document to create an element.
3823
0
  nsIDocument* doc = window->GetExtantDoc();
3824
0
  if (!doc) {
3825
0
    return Throw(aCx, NS_ERROR_UNEXPECTED);
3826
0
  }
3827
0
3828
0
  // Step 2.
3829
0
3830
0
  // The newTarget might be a cross-compartment wrapper. Get the underlying
3831
0
  // object so we can do the spec's object-identity checks.  If we ever stop
3832
0
  // unwrapping here, carefully audit uses of newTarget below!
3833
0
  JS::Rooted<JSObject*> newTarget(aCx, js::CheckedUnwrap(&args.newTarget().toObject()));
3834
0
  if (!newTarget) {
3835
0
    return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3836
0
  }
3837
0
3838
0
  // Enter the compartment of our underlying newTarget object, so we end
3839
0
  // up comparing to the constructor object for our interface from that global.
3840
0
  // XXXbz This is not what the spec says to do, and it's not super-clear to me
3841
0
  // at this point why we're doing it.  Why not just compare |newTarget| and
3842
0
  // |callee| if the intent is just to prevent registration of HTML interface
3843
0
  // objects as constructors?  Of course it's not clear that the spec check
3844
0
  // makes sense to start with: https://github.com/whatwg/html/issues/3575
3845
0
  {
3846
0
    JSAutoRealm ar(aCx, newTarget);
3847
0
    JS::Handle<JSObject*> constructor =
3848
0
      GetPerInterfaceObjectHandle(aCx, aConstructorId, aCreator,
3849
0
                                  true);
3850
0
    if (!constructor) {
3851
0
      return false;
3852
0
    }
3853
0
    if (newTarget == constructor) {
3854
0
      return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3855
0
    }
3856
0
  }
3857
0
3858
0
  // Step 3.
3859
0
  CustomElementDefinition* definition =
3860
0
    registry->LookupCustomElementDefinition(aCx, newTarget);
3861
0
  if (!definition) {
3862
0
    return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3863
0
  }
3864
0
3865
0
  // Steps 4 and 5 do some sanity checks on our callee.  We add to those a
3866
0
  // determination of what sort of element we're planning to construct.
3867
0
  // Technically, this should happen (implicitly) in step 8, but this
3868
0
  // determination is side-effect-free, so it's OK.
3869
0
  int32_t ns = definition->mNamespaceID;
3870
0
3871
0
  constructorGetterCallback cb = nullptr;
3872
0
  if (ns == kNameSpaceID_XUL) {
3873
0
    if (definition->mLocalName == nsGkAtoms::menupopup ||
3874
0
        definition->mLocalName == nsGkAtoms::popup ||
3875
0
        definition->mLocalName == nsGkAtoms::panel ||
3876
0
        definition->mLocalName == nsGkAtoms::tooltip) {
3877
0
      cb = XULPopupElement_Binding::GetConstructorObject;
3878
0
    } else if (definition->mLocalName == nsGkAtoms::iframe ||
3879
0
                definition->mLocalName == nsGkAtoms::browser ||
3880
0
                definition->mLocalName == nsGkAtoms::editor) {
3881
0
      cb = XULFrameElement_Binding::GetConstructorObject;
3882
0
    } else if (definition->mLocalName == nsGkAtoms::menu ||
3883
0
               definition->mLocalName == nsGkAtoms::menulist) {
3884
0
      cb = XULMenuElement_Binding::GetConstructorObject;
3885
0
    } else if (definition->mLocalName == nsGkAtoms::scrollbox) {
3886
0
      cb = XULScrollElement_Binding::GetConstructorObject;
3887
0
    } else {
3888
0
      cb = XULElement_Binding::GetConstructorObject;
3889
0
    }
3890
0
  }
3891
0
3892
0
  int32_t tag = eHTMLTag_userdefined;
3893
0
  if (!definition->IsCustomBuiltIn()) {
3894
0
    // Step 4.
3895
0
    // If the definition is for an autonomous custom element, the active
3896
0
    // function should be HTMLElement or extend from XULElement.
3897
0
    if (!cb) {
3898
0
      cb = HTMLElement_Binding::GetConstructorObject;
3899
0
    }
3900
0
3901
0
    // We want to get the constructor from our global's realm, not the
3902
0
    // caller realm.
3903
0
    JSAutoRealm ar(aCx, global.Get());
3904
0
    JS::Rooted<JSObject*> constructor(aCx, cb(aCx));
3905
0
3906
0
    if (constructor != js::CheckedUnwrap(callee)) {
3907
0
      return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3908
0
    }
3909
0
  } else {
3910
0
    if (ns == kNameSpaceID_XHTML) {
3911
0
      // Step 5.
3912
0
      // If the definition is for a customized built-in element, the localName
3913
0
      // should be one of the ones defined in the specification for this interface.
3914
0
      tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
3915
0
      if (tag == eHTMLTag_userdefined) {
3916
0
        return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3917
0
      }
3918
0
3919
0
      MOZ_ASSERT(tag <= NS_HTML_TAG_MAX, "tag is out of bounds");
3920
0
3921
0
      // If the definition is for a customized built-in element, the active
3922
0
      // function should be the localname's element interface.
3923
0
      cb = sConstructorGetterCallback[tag];
3924
0
    }
3925
0
3926
0
    if (!cb) {
3927
0
      return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3928
0
    }
3929
0
3930
0
    // We want to get the constructor from our global's realm, not the
3931
0
    // caller realm.
3932
0
    JSAutoRealm ar(aCx, global.Get());
3933
0
    JS::Rooted<JSObject*> constructor(aCx, cb(aCx));
3934
0
    if (!constructor) {
3935
0
      return false;
3936
0
    }
3937
0
3938
0
    if (constructor != js::CheckedUnwrap(callee)) {
3939
0
      return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
3940
0
    }
3941
0
  }
3942
0
3943
0
  // Step 6.
3944
0
  JS::Rooted<JSObject*> desiredProto(aCx);
3945
0
  if (!GetDesiredProto(aCx, args, &desiredProto)) {
3946
0
    return false;
3947
0
  }
3948
0
3949
0
  // Step 7.
3950
0
  if (!desiredProto) {
3951
0
    // This fallback behavior is designed to match analogous behavior for the
3952
0
    // JavaScript built-ins. So we enter the realm of our underlying newTarget
3953
0
    // object and fall back to the prototype object from that global.
3954
0
    // XXX The spec says to use GetFunctionRealm(), which is not actually
3955
0
    // the same thing as what we have here (e.g. in the case of scripted callable proxies
3956
0
    // whose target is not same-realm with the proxy, or bound functions, etc).
3957
0
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658
3958
0
    {
3959
0
      JSAutoRealm ar(aCx, newTarget);
3960
0
      desiredProto = GetPerInterfaceObjectHandle(aCx, aProtoId, aCreator, true);
3961
0
      if (!desiredProto) {
3962
0
          return false;
3963
0
      }
3964
0
    }
3965
0
3966
0
    // desiredProto is in the realm of the underlying newTarget object.
3967
0
    // Wrap it into the context realm.
3968
0
    if (!JS_WrapObject(aCx, &desiredProto)) {
3969
0
      return false;
3970
0
    }
3971
0
  }
3972
0
3973
0
  // We need to do some work to actually return an Element, so we do step 8 on
3974
0
  // one branch and steps 9-12 on another branch, then common up the "return
3975
0
  // element" work.
3976
0
  RefPtr<Element> element;
3977
0
  nsTArray<RefPtr<Element>>& constructionStack =
3978
0
    definition->mConstructionStack;
3979
0
  if (constructionStack.IsEmpty()) {
3980
0
    // Step 8.
3981
0
    // Now we go to construct an element.  We want to do this in global's
3982
0
    // realm, not caller realm (the normal constructor behavior),
3983
0
    // just in case those elements create JS things.
3984
0
    JSAutoRealm ar(aCx, global.Get());
3985
0
    AutoConstructionDepth acd(definition);
3986
0
3987
0
    RefPtr<NodeInfo> nodeInfo =
3988
0
      doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
3989
0
                                          definition->mPrefixStack.LastElement(),
3990
0
                                          ns,
3991
0
                                          nsINode::ELEMENT_NODE);
3992
0
    MOZ_ASSERT(nodeInfo);
3993
0
3994
0
    if (ns == kNameSpaceID_XUL) {
3995
0
      element = nsXULElement::Construct(nodeInfo.forget());
3996
0
3997
0
    } else {
3998
0
      if (tag == eHTMLTag_userdefined) {
3999
0
        // Autonomous custom element.
4000
0
        element = NS_NewHTMLElement(nodeInfo.forget());
4001
0
      } else {
4002
0
        // Customized built-in element.
4003
0
        element = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
4004
0
      }
4005
0
    }
4006
0
4007
0
    element->SetCustomElementData(
4008
0
      new CustomElementData(definition->mType, CustomElementData::State::eCustom));
4009
0
4010
0
    element->SetCustomElementDefinition(definition);
4011
0
  } else {
4012
0
    // Step 9.
4013
0
    element = constructionStack.LastElement();
4014
0
4015
0
    // Step 10.
4016
0
    if (element == ALREADY_CONSTRUCTED_MARKER) {
4017
0
      return Throw(aCx, NS_ERROR_DOM_INVALID_STATE_ERR);
4018
0
    }
4019
0
4020
0
    // Step 11.
4021
0
    // Do prototype swizzling for upgrading a custom element here, for cases
4022
0
    // when we have a reflector already.  If we don't have one yet, we will
4023
0
    // create it with the right proto (by calling DoGetOrCreateDOMReflector with
4024
0
    // that proto).
4025
0
    JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
4026
0
    if (reflector) {
4027
0
      // reflector might be in different realm.
4028
0
      JSAutoRealm ar(aCx, reflector);
4029
0
      JS::Rooted<JSObject*> givenProto(aCx, desiredProto);
4030
0
      if (!JS_WrapObject(aCx, &givenProto) ||
4031
0
          !JS_SetPrototype(aCx, reflector, givenProto)) {
4032
0
        return false;
4033
0
      }
4034
0
    }
4035
0
4036
0
    // Step 12.
4037
0
    constructionStack.LastElement() = ALREADY_CONSTRUCTED_MARKER;
4038
0
  }
4039
0
4040
0
  // Tail end of step 8 and step 13: returning the element.  We want to do this
4041
0
  // part in the global's realm, though in practice it won't matter much
4042
0
  // because Element always knows which realm it should be created in.
4043
0
  JSAutoRealm ar(aCx, global.Get());
4044
0
  if (!js::IsObjectInContextCompartment(desiredProto, aCx) &&
4045
0
      !JS_WrapObject(aCx, &desiredProto)) {
4046
0
    return false;
4047
0
  }
4048
0
4049
0
  return GetOrCreateDOMReflector(aCx, element, args.rval(), desiredProto);
4050
0
}
4051
} // namespace binding_detail
4052
4053
#ifdef DEBUG
4054
namespace binding_detail {
4055
void
4056
AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
4057
                             JS::Handle<JSObject*> aGivenProto)
4058
{
4059
  if (!aGivenProto) {
4060
    // Nothing to assert here
4061
    return;
4062
  }
4063
4064
  JS::Rooted<JSObject*> reflector(aCx, aReflector);
4065
  JSAutoRealm ar(aCx, reflector);
4066
  JS::Rooted<JSObject*> reflectorProto(aCx);
4067
  bool ok = JS_GetPrototype(aCx, reflector, &reflectorProto);
4068
  MOZ_ASSERT(ok);
4069
  // aGivenProto may not be in the right realm here, so we
4070
  // have to wrap it to compare.
4071
  JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
4072
  ok = JS_WrapObject(aCx, &givenProto);
4073
  MOZ_ASSERT(ok);
4074
  MOZ_ASSERT(givenProto == reflectorProto,
4075
             "How are we supposed to change the proto now?");
4076
}
4077
} // namespace binding_detail
4078
#endif // DEBUG
4079
4080
void
4081
SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter)
4082
0
{
4083
0
  nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
4084
0
  if (win && win->GetDocument()) {
4085
0
    win->GetDocument()->SetDocumentAndPageUseCounter(aUseCounter);
4086
0
  }
4087
0
}
4088
4089
namespace {
4090
4091
// This runnable is used to write a deprecation message from a worker to the
4092
// console running on the main-thread.
4093
class DeprecationWarningRunnable final : public WorkerProxyToMainThreadRunnable
4094
{
4095
  nsIDocument::DeprecatedOperations mOperation;
4096
4097
public:
4098
  explicit DeprecationWarningRunnable(nsIDocument::DeprecatedOperations aOperation)
4099
    : mOperation(aOperation)
4100
0
  {}
4101
4102
private:
4103
  void
4104
  RunOnMainThread(WorkerPrivate* aWorkerPrivate) override
4105
0
  {
4106
0
    MOZ_ASSERT(NS_IsMainThread());
4107
0
    MOZ_ASSERT(aWorkerPrivate);
4108
0
4109
0
    // Walk up to our containing page
4110
0
    WorkerPrivate* wp = aWorkerPrivate;
4111
0
    while (wp->GetParent()) {
4112
0
      wp = wp->GetParent();
4113
0
    }
4114
0
4115
0
    nsPIDOMWindowInner* window = wp->GetWindow();
4116
0
    if (window && window->GetExtantDoc()) {
4117
0
      window->GetExtantDoc()->WarnOnceAbout(mOperation);
4118
0
    }
4119
0
  }
4120
4121
  void
4122
  RunBackOnWorkerThreadForCleanup(WorkerPrivate* aWorkerPrivate) override
4123
0
  {}
4124
};
4125
4126
} // anonymous namespace
4127
4128
void
4129
DeprecationWarning(JSContext* aCx, JSObject* aObject,
4130
                   nsIDocument::DeprecatedOperations aOperation)
4131
0
{
4132
0
  GlobalObject global(aCx, aObject);
4133
0
  if (global.Failed()) {
4134
0
    NS_ERROR("Could not create global for DeprecationWarning");
4135
0
    return;
4136
0
  }
4137
0
4138
0
  DeprecationWarning(global, aOperation);
4139
0
}
4140
4141
void
4142
DeprecationWarning(const GlobalObject& aGlobal,
4143
                   nsIDocument::DeprecatedOperations aOperation)
4144
0
{
4145
0
  if (NS_IsMainThread()) {
4146
0
    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
4147
0
    if (window && window->GetExtantDoc()) {
4148
0
      window->GetExtantDoc()->WarnOnceAbout(aOperation);
4149
0
    }
4150
0
4151
0
    return;
4152
0
  }
4153
0
4154
0
  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aGlobal.Context());
4155
0
  if (!workerPrivate) {
4156
0
    return;
4157
0
  }
4158
0
4159
0
  RefPtr<DeprecationWarningRunnable> runnable =
4160
0
    new DeprecationWarningRunnable(aOperation);
4161
0
  runnable->Dispatch(workerPrivate);
4162
0
}
4163
4164
namespace binding_detail {
4165
JSObject*
4166
UnprivilegedJunkScopeOrWorkerGlobal()
4167
0
{
4168
0
  if (NS_IsMainThread()) {
4169
0
    return xpc::UnprivilegedJunkScope();
4170
0
  }
4171
0
4172
0
  return GetCurrentThreadWorkerGlobal();
4173
0
}
4174
} // namespace binding_detail
4175
4176
JS::Handle<JSObject*>
4177
GetPerInterfaceObjectHandle(JSContext* aCx,
4178
                            size_t aSlotId,
4179
                            CreateInterfaceObjectsMethod aCreator,
4180
                            bool aDefineOnGlobal)
4181
4
{
4182
4
  /* Make sure our global is sane.  Hopefully we can remove this sometime */
4183
4
  JSObject* global = JS::CurrentGlobalOrNull(aCx);
4184
4
  if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
4185
0
    return nullptr;
4186
0
  }
4187
4
4188
4
  /* Check to see whether the interface objects are already installed */
4189
4
  ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
4190
4
  if (!protoAndIfaceCache.HasEntryInSlot(aSlotId)) {
4191
2
    JS::Rooted<JSObject*> rootedGlobal(aCx, global);
4192
2
    aCreator(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
4193
2
  }
4194
4
4195
4
  /*
4196
4
   * The object might _still_ be null, but that's OK.
4197
4
   *
4198
4
   * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
4199
4
   * traced by TraceProtoAndIfaceCache() and its contents are never
4200
4
   * changed after they have been set.
4201
4
   *
4202
4
   * Calling address() avoids the read barrier that does gray unmarking, but
4203
4
   * it's not possible for the object to be gray here.
4204
4
   */
4205
4
4206
4
  const JS::Heap<JSObject*>& entrySlot =
4207
4
    protoAndIfaceCache.EntrySlotMustExist(aSlotId);
4208
4
  MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
4209
4
  return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
4210
4
}
4211
4212
namespace binding_detail {
4213
bool
4214
IsGetterEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
4215
                JSJitGetterOp aGetter,
4216
                const Prefable<const JSPropertySpec>* aAttributes)
4217
0
{
4218
0
  MOZ_ASSERT(aAttributes);
4219
0
  MOZ_ASSERT(aAttributes->specs);
4220
0
  do {
4221
0
    if (aAttributes->isEnabled(aCx, aObj)) {
4222
0
      const JSPropertySpec* specs = aAttributes->specs;
4223
0
      do {
4224
0
        MOZ_ASSERT(specs->isAccessor());
4225
0
        if (specs->isSelfHosted()) {
4226
0
          // It won't have a JSJitGetterOp.
4227
0
          continue;
4228
0
        }
4229
0
        const JSJitInfo* info = specs->accessors.getter.native.info;
4230
0
        if (!info) {
4231
0
          continue;
4232
0
        }
4233
0
        MOZ_ASSERT(info->type() == JSJitInfo::OpType::Getter);
4234
0
        if (info->getter == aGetter) {
4235
0
          return true;
4236
0
        }
4237
0
      } while ((++specs)->name);
4238
0
    }
4239
0
  } while ((++aAttributes)->specs);
4240
0
4241
0
  // Didn't find it.
4242
0
  return false;
4243
0
}
4244
4245
} // namespace binding_detail
4246
4247
} // namespace dom
4248
} // namespace mozilla