Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsJSUtils.h
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
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef nsJSUtils_h__
8
#define nsJSUtils_h__
9
10
/**
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.
15
 */
16
17
#include "mozilla/Assertions.h"
18
19
#include "GeckoProfiler.h"
20
#include "jsapi.h"
21
#include "jsfriendapi.h"
22
#include "js/Conversions.h"
23
#include "js/StableStringChars.h"
24
#include "nsString.h"
25
26
class nsIScriptContext;
27
class nsIScriptElement;
28
class nsIScriptGlobalObject;
29
class nsXBLPrototypeBinding;
30
31
namespace mozilla {
32
namespace dom {
33
class AutoJSAPI;
34
class Element;
35
} // namespace dom
36
} // namespace mozilla
37
38
class nsJSUtils
39
{
40
public:
41
  static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
42
                                 uint32_t* aLineno = nullptr,
43
                                 uint32_t* aColumn = nullptr);
44
  static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
45
                                 uint32_t* aLineno = nullptr,
46
                                 uint32_t* aColumn = nullptr);
47
48
  /**
49
   * Retrieve the inner window ID based on the given JSContext.
50
   *
51
   * @param JSContext aContext
52
   *        The JSContext from which you want to find the inner window ID.
53
   *
54
   * @returns uint64_t the inner window ID.
55
   */
56
  static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext);
57
58
  static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
59
                                  JS::AutoObjectVector& aScopeChain,
60
                                  JS::CompileOptions& aOptions,
61
                                  const nsACString& aName,
62
                                  uint32_t aArgCount,
63
                                  const char** aArgArray,
64
                                  const nsAString& aBody,
65
                                  JSObject** aFunctionObject);
66
67
68
  // ExecutionContext is used to switch compartment.
69
  class MOZ_STACK_CLASS ExecutionContext {
70
#ifdef MOZ_GECKO_PROFILER
71
    // Register stack annotations for the Gecko profiler.
72
    mozilla::AutoProfilerLabel mAutoProfilerLabel;
73
#endif
74
75
    JSContext* mCx;
76
77
    // Handles switching to our global's realm.
78
    JSAutoRealm mRealm;
79
80
    // Set to a valid handle if a return value is expected.
81
    JS::Rooted<JS::Value> mRetValue;
82
83
    // Scope chain in which the execution takes place.
84
    JS::AutoObjectVector mScopeChain;
85
86
    // returned value forwarded when we have to interupt the execution eagerly
87
    // with mSkip.
88
    nsresult mRv;
89
90
    // Used to skip upcoming phases in case of a failure.  In such case the
91
    // result is carried by mRv.
92
    bool mSkip;
93
94
    // Should the result be serialized before being returned.
95
    bool mCoerceToString;
96
97
    // Encode the bytecode before it is being executed.
98
    bool mEncodeBytecode;
99
100
#ifdef DEBUG
101
    // Should we set the return value.
102
    bool mWantsReturnValue;
103
104
    bool mExpectScopeChain;
105
#endif
106
107
   public:
108
109
    // Enter compartment in which the code would be executed.  The JSContext
110
    // must come from an AutoEntryScript.
111
    ExecutionContext(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
112
113
    ExecutionContext(const ExecutionContext&) = delete;
114
    ExecutionContext(ExecutionContext&&) = delete;
115
116
0
    ~ExecutionContext() {
117
0
      // This flag is resetted, when the returned value is extracted.
118
0
      MOZ_ASSERT(!mWantsReturnValue);
119
0
    }
120
121
    // The returned value would be converted to a string if the
122
    // |aCoerceToString| is flag set.
123
0
    ExecutionContext& SetCoerceToString(bool aCoerceToString) {
124
0
      mCoerceToString = aCoerceToString;
125
0
      return *this;
126
0
    }
127
128
    // When set, this flag records and encodes the bytecode as soon as it is
129
    // being compiled, and before it is being executed. The bytecode can then be
130
    // requested by using |JS::FinishIncrementalEncoding| with the mutable
131
    // handle |aScript| argument of |CompileAndExec| or |JoinAndExec|.
132
0
    ExecutionContext& SetEncodeBytecode(bool aEncodeBytecode) {
133
0
      mEncodeBytecode = aEncodeBytecode;
134
0
      return *this;
135
0
    }
136
137
    // Set the scope chain in which the code should be executed.
138
    void SetScopeChain(const JS::AutoObjectVector& aScopeChain);
139
140
    // Copy the returned value in the mutable handle argument, in case of a
141
    // evaluation failure either during the execution or the conversion of the
142
    // result to a string, the nsresult would be set to the corresponding result
143
    // code, and the mutable handle argument would remain unchanged.
144
    //
145
    // The value returned in the mutable handle argument is part of the
146
    // compartment given as argument to the ExecutionContext constructor. If the
147
    // caller is in a different compartment, then the out-param value should be
148
    // wrapped by calling |JS_WrapValue|.
149
    MOZ_MUST_USE nsresult
150
    ExtractReturnValue(JS::MutableHandle<JS::Value> aRetValue);
151
152
    // After getting a notification that an off-thread compilation terminated,
153
    // this function will take the result of the parser by moving it to the main
154
    // thread before starting the execution of the script.
155
    //
156
    // The compiled script would be returned in the |aScript| out-param.
157
    MOZ_MUST_USE nsresult JoinAndExec(JS::OffThreadToken** aOffThreadToken,
158
                                      JS::MutableHandle<JSScript*> aScript);
159
160
    // Compile a script contained in a SourceBuffer, and execute it.
161
    nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
162
                            JS::SourceBufferHolder& aSrcBuf,
163
                            JS::MutableHandle<JSScript*> aScript);
164
165
    // Compile a script contained in a string, and execute it.
166
    nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
167
                            const nsAString& aScript);
168
169
    // Decode a script contained in a buffer, and execute it.
170
    MOZ_MUST_USE nsresult DecodeAndExec(JS::CompileOptions& aCompileOptions,
171
                                        mozilla::Vector<uint8_t>& aBytecodeBuf,
172
                                        size_t aBytecodeIndex);
173
174
    // After getting a notification that an off-thread decoding terminated, this
175
    // function will get the result of the decoder by moving it to the main
176
    // thread before starting the execution of the script.
177
    MOZ_MUST_USE nsresult DecodeJoinAndExec(JS::OffThreadToken** aOffThreadToken);
178
179
    MOZ_MUST_USE nsresult DecodeBinASTJoinAndExec(JS::OffThreadToken** aOffThreadToken,
180
                                                  JS::MutableHandle<JSScript*> aScript);
181
182
    // Decode a BinAST encoded script contained in a buffer, and execute it.
183
    nsresult DecodeBinASTAndExec(JS::CompileOptions& aCompileOptions,
184
                                 const uint8_t* aBuf, size_t aLength,
185
                                 JS::MutableHandle<JSScript*> aScript);
186
  };
187
188
  static nsresult CompileModule(JSContext* aCx,
189
                                JS::SourceBufferHolder& aSrcBuf,
190
                                JS::Handle<JSObject*> aEvaluationGlobal,
191
                                JS::CompileOptions &aCompileOptions,
192
                                JS::MutableHandle<JSScript*> aScript);
193
194
  static nsresult InitModuleSourceElement(JSContext* aCx,
195
                                          JS::Handle<JSScript*> aScript,
196
                                          nsIScriptElement* aElement);
197
198
  static nsresult ModuleInstantiate(JSContext* aCx,
199
                                    JS::Handle<JSScript*> aScript);
200
201
  static nsresult ModuleEvaluate(JSContext* aCx,
202
                                 JS::Handle<JSScript*> aScript);
203
204
  // Returns false if an exception got thrown on aCx.  Passing a null
205
  // aElement is allowed; that wil produce an empty aScopeChain.
206
  static bool GetScopeChainForElement(JSContext* aCx,
207
                                      mozilla::dom::Element* aElement,
208
                                      JS::AutoObjectVector& aScopeChain);
209
210
  // Returns a scope chain suitable for XBL execution.
211
  //
212
  // This is by default GetScopeChainForElemenet, but will be different if the
213
  // <binding> element had the simpleScopeChain attribute.
214
  //
215
  // This is to prevent footguns like bug 1446342.
216
  static bool GetScopeChainForXBL(JSContext* aCx,
217
                                  mozilla::dom::Element* aBoundElement,
218
                                  const nsXBLPrototypeBinding& aProtoBinding,
219
                                  JS::AutoObjectVector& aScopeChain);
220
221
  static void ResetTimeZone();
222
};
223
224
template<typename T>
225
inline bool
226
AssignJSString(JSContext *cx, T &dest, JSString *s)
227
14
{
228
14
  size_t len = JS::GetStringLength(s);
229
14
  static_assert(js::MaxStringLength < (1 << 28),
230
14
                "Shouldn't overflow here or in SetCapacity");
231
14
  if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
232
0
    JS_ReportOutOfMemory(cx);
233
0
    return false;
234
0
  }
235
14
  return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
236
14
}
Unexecuted instantiation: bool AssignJSString<nsAutoJSString>(JSContext*, nsAutoJSString&, JSString*)
Unexecuted instantiation: bool AssignJSString<nsTString<char16_t> >(JSContext*, nsTString<char16_t>&, JSString*)
bool AssignJSString<mozilla::dom::binding_detail::FakeString>(JSContext*, mozilla::dom::binding_detail::FakeString&, JSString*)
Line
Count
Source
227
14
{
228
14
  size_t len = JS::GetStringLength(s);
229
14
  static_assert(js::MaxStringLength < (1 << 28),
230
14
                "Shouldn't overflow here or in SetCapacity");
231
14
  if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
232
0
    JS_ReportOutOfMemory(cx);
233
0
    return false;
234
0
  }
235
14
  return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
236
14
}
Unexecuted instantiation: bool AssignJSString<nsTSubstring<char16_t> >(JSContext*, nsTSubstring<char16_t>&, JSString*)
Unexecuted instantiation: bool AssignJSString<nsTAutoStringN<char16_t, 64ul> >(JSContext*, nsTAutoStringN<char16_t, 64ul>&, JSString*)
237
238
inline void
239
AssignJSFlatString(nsAString &dest, JSFlatString *s)
240
0
{
241
0
  size_t len = js::GetFlatStringLength(s);
242
0
  static_assert(js::MaxStringLength < (1 << 28),
243
0
                "Shouldn't overflow here or in SetCapacity");
244
0
  dest.SetLength(len);
245
0
  js::CopyFlatStringChars(dest.BeginWriting(), s, len);
246
0
}
247
248
class nsAutoJSString : public nsAutoString
249
{
250
public:
251
252
  /**
253
   * nsAutoJSString should be default constructed, which leaves it empty
254
   * (this->IsEmpty()), and initialized with one of the init() methods below.
255
   */
256
0
  nsAutoJSString() {}
257
258
  bool init(JSContext* aContext, JSString* str)
259
0
  {
260
0
    return AssignJSString(aContext, *this, str);
261
0
  }
262
263
  bool init(JSContext* aContext, const JS::Value &v)
264
0
  {
265
0
    if (v.isString()) {
266
0
      return init(aContext, v.toString());
267
0
    }
268
0
269
0
    // Stringify, making sure not to run script.
270
0
    JS::Rooted<JSString*> str(aContext);
271
0
    if (v.isObject()) {
272
0
      str = JS_NewStringCopyZ(aContext, "[Object]");
273
0
    } else {
274
0
      JS::Rooted<JS::Value> rootedVal(aContext, v);
275
0
      str = JS::ToString(aContext, rootedVal);
276
0
    }
277
0
278
0
    return str && init(aContext, str);
279
0
  }
280
281
  bool init(JSContext* aContext, jsid id)
282
0
  {
283
0
    JS::Rooted<JS::Value> v(aContext);
284
0
    return JS_IdToValue(aContext, id, &v) && init(aContext, v);
285
0
  }
286
287
  bool init(const JS::Value &v);
288
289
0
  ~nsAutoJSString() {}
290
};
291
292
#endif /* nsJSUtils_h__ */