1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11 * This is not a generated file. It contains common utility functions
12 * invoked from the JavaScript code generated from IDL interfaces.
13 * The goal of the utility functions is to cut down on the size of
14 * the generated code itself.
17 #include "mozilla/Assertions.h"
20 #include "js/CompileOptions.h"
21 #include "js/Conversions.h"
22 #include "js/SourceText.h"
23 #include "js/String.h" // JS::{,Lossy}CopyLinearStringChars, JS::CopyStringChars, JS::Get{,Linear}StringLength, JS::MaxStringLength, JS::StringHasLatin1Chars
24 #include "js/Utility.h" // JS::FreePolicy
26 #include "xpcpublic.h"
28 class nsIScriptContext
;
29 class nsIScriptElement
;
30 class nsIScriptGlobalObject
;
31 class nsXBLPrototypeBinding
;
40 } // namespace mozilla
44 static bool GetCallingLocation(JSContext
* aContext
, nsACString
& aFilename
,
45 uint32_t* aLineno
= nullptr,
46 uint32_t* aColumn
= nullptr);
47 static bool GetCallingLocation(JSContext
* aContext
, nsAString
& aFilename
,
48 uint32_t* aLineno
= nullptr,
49 uint32_t* aColumn
= nullptr);
52 * Retrieve the inner window ID based on the given JSContext.
54 * @param JSContext aContext
55 * The JSContext from which you want to find the inner window ID.
57 * @returns uint64_t the inner window ID.
59 static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext
* aContext
);
61 static nsresult
CompileFunction(mozilla::dom::AutoJSAPI
& jsapi
,
62 JS::HandleVector
<JSObject
*> aScopeChain
,
63 JS::CompileOptions
& aOptions
,
64 const nsACString
& aName
, uint32_t aArgCount
,
65 const char** aArgArray
,
66 const nsAString
& aBody
,
67 JSObject
** aFunctionObject
);
69 static nsresult
UpdateFunctionDebugMetadata(
70 mozilla::dom::AutoJSAPI
& jsapi
, JS::Handle
<JSObject
*> aFun
,
71 JS::CompileOptions
& aOptions
, JS::Handle
<JSString
*> aElementAttributeName
,
72 JS::Handle
<JS::Value
> aPrivateValue
);
74 static bool IsScriptable(JS::Handle
<JSObject
*> aEvaluationGlobal
);
76 // Returns false if an exception got thrown on aCx. Passing a null
77 // aElement is allowed; that wil produce an empty aScopeChain.
78 static bool GetScopeChainForElement(
79 JSContext
* aCx
, mozilla::dom::Element
* aElement
,
80 JS::MutableHandleVector
<JSObject
*> aScopeChain
);
82 static void ResetTimeZone();
84 static bool DumpEnabled();
86 // A helper function that receives buffer pointer, creates ArrayBuffer, and
87 // convert it to Uint8Array.
88 // Note that the buffer needs to be created by JS_malloc (or at least can be
89 // freed by JS_free), as the resulting Uint8Array takes the ownership of the
91 static JSObject
* MoveBufferAsUint8Array(
92 JSContext
* aCx
, size_t aSize
,
93 mozilla::UniquePtr
<uint8_t[], JS::FreePolicy
> aBuffer
);
96 inline void AssignFromStringBuffer(nsStringBuffer
* buffer
, size_t len
,
98 buffer
->ToString(len
, dest
);
101 template <typename T
, typename
std::enable_if_t
<std::is_same
<
102 typename
T::char_type
, char16_t
>::value
>* = nullptr>
103 inline bool AssignJSString(JSContext
* cx
, T
& dest
, JSString
* s
) {
104 size_t len
= JS::GetStringLength(s
);
105 static_assert(JS::MaxStringLength
< (1 << 30),
106 "Shouldn't overflow here or in SetCapacity");
108 const char16_t
* chars
;
109 if (XPCStringConvert::MaybeGetDOMStringChars(s
, &chars
)) {
110 // The characters represent an existing string buffer that we shared with
111 // JS. We can share that buffer ourselves if the string corresponds to the
112 // whole buffer; otherwise we have to copy.
113 if (chars
[len
] == '\0') {
114 AssignFromStringBuffer(
115 nsStringBuffer::FromData(const_cast<char16_t
*>(chars
)), len
, dest
);
118 } else if (XPCStringConvert::MaybeGetLiteralStringChars(s
, &chars
)) {
119 // The characters represent a literal char16_t string constant
120 // compiled into libxul; we can just use it as-is.
121 dest
.AssignLiteral(chars
, len
);
125 // We don't bother checking for a dynamic-atom external string, because we'd
126 // just need to copy out of it anyway.
128 if (MOZ_UNLIKELY(!dest
.SetLength(len
, mozilla::fallible
))) {
129 JS_ReportOutOfMemory(cx
);
132 return JS::CopyStringChars(cx
, dest
.BeginWriting(), s
, len
);
135 // Specialization for UTF8String.
136 template <typename T
, typename
std::enable_if_t
<std::is_same
<
137 typename
T::char_type
, char>::value
>* = nullptr>
138 inline bool AssignJSString(JSContext
* cx
, T
& dest
, JSString
* s
) {
139 using namespace mozilla
;
140 CheckedInt
<size_t> bufLen(JS::GetStringLength(s
));
141 // From the contract for JS_EncodeStringToUTF8BufferPartial, to guarantee that
142 // the whole string is converted.
143 if (JS::StringHasLatin1Chars(s
)) {
149 if (MOZ_UNLIKELY(!bufLen
.isValid())) {
150 JS_ReportOutOfMemory(cx
);
154 // Shouldn't really matter, but worth being safe.
155 const bool kAllowShrinking
= true;
157 auto handleOrErr
= dest
.BulkWrite(bufLen
.value(), 0, kAllowShrinking
);
158 if (MOZ_UNLIKELY(handleOrErr
.isErr())) {
159 JS_ReportOutOfMemory(cx
);
163 auto handle
= handleOrErr
.unwrap();
165 auto maybe
= JS_EncodeStringToUTF8BufferPartial(cx
, s
, handle
.AsSpan());
166 if (MOZ_UNLIKELY(!maybe
)) {
167 JS_ReportOutOfMemory(cx
);
173 std::tie(read
, written
) = *maybe
;
175 MOZ_ASSERT(read
== JS::GetStringLength(s
));
176 handle
.Finish(written
, kAllowShrinking
);
180 inline void AssignJSLinearString(nsAString
& dest
, JSLinearString
* s
) {
181 size_t len
= JS::GetLinearStringLength(s
);
182 static_assert(JS::MaxStringLength
< (1 << 30),
183 "Shouldn't overflow here or in SetCapacity");
185 JS::CopyLinearStringChars(dest
.BeginWriting(), s
, len
);
188 inline void AssignJSLinearString(nsACString
& dest
, JSLinearString
* s
) {
189 size_t len
= JS::GetLinearStringLength(s
);
190 static_assert(JS::MaxStringLength
< (1 << 30),
191 "Shouldn't overflow here or in SetCapacity");
193 JS::LossyCopyLinearStringChars(dest
.BeginWriting(), s
, len
);
196 template <typename T
>
197 class nsTAutoJSLinearString
: public nsTAutoString
<T
> {
199 explicit nsTAutoJSLinearString(JSLinearString
* str
) {
200 AssignJSLinearString(*this, str
);
204 using nsAutoJSLinearString
= nsTAutoJSLinearString
<char16_t
>;
205 using nsAutoJSLinearCString
= nsTAutoJSLinearString
<char>;
207 template <typename T
>
208 class nsTAutoJSString
: public nsTAutoString
<T
> {
211 * nsTAutoJSString should be default constructed, which leaves it empty
212 * (this->IsEmpty()), and initialized with one of the init() methods below.
214 nsTAutoJSString() = default;
216 bool init(JSContext
* aContext
, JSString
* str
) {
217 return AssignJSString(aContext
, *this, str
);
220 bool init(JSContext
* aContext
, const JS::Value
& v
) {
222 return init(aContext
, v
.toString());
225 // Stringify, making sure not to run script.
226 JS::Rooted
<JSString
*> str(aContext
);
228 str
= JS_NewStringCopyZ(aContext
, "[Object]");
230 JS::Rooted
<JS::Value
> rootedVal(aContext
, v
);
231 str
= JS::ToString(aContext
, rootedVal
);
234 return str
&& init(aContext
, str
);
237 bool init(JSContext
* aContext
, jsid id
) {
238 JS::Rooted
<JS::Value
> v(aContext
);
239 return JS_IdToValue(aContext
, id
, &v
) && init(aContext
, v
);
242 bool init(const JS::Value
& v
);
244 ~nsTAutoJSString() = default;
247 using nsAutoJSString
= nsTAutoJSString
<char16_t
>;
249 // Note that this is guaranteed to be UTF-8.
250 using nsAutoJSCString
= nsTAutoJSString
<char>;
252 #endif /* nsJSUtils_h__ */