summaryrefslogtreecommitdiffstats
path: root/dom/base/JSExecutionContext.h
blob: f6bfbdc628efde22cb478f72d904c9f6c7aa4162 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef DOM_BASE_JSEXECUTIONCONTEXT_H_
#define DOM_BASE_JSEXECUTIONCONTEXT_H_

#include "js/GCVector.h"
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "js/experimental/JSStencil.h"
#include "jsapi.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/Vector.h"
#include "nsStringFwd.h"
#include "nscore.h"

class nsIScriptContext;
class nsIScriptElement;
class nsIScriptGlobalObject;
class nsXBLPrototypeBinding;

namespace mozilla {
union Utf8Unit;

namespace dom {

class ScriptLoadContext;

class MOZ_STACK_CLASS JSExecutionContext final {
  // Register stack annotations for the Gecko profiler.
  mozilla::AutoProfilerLabel mAutoProfilerLabel;

  JSContext* mCx;

  // Handles switching to our global's realm.
  JSAutoRealm mRealm;

  // Set to a valid handle if a return value is expected.
  JS::Rooted<JS::Value> mRetValue;

  // The compiled script.
  JS::Rooted<JSScript*> mScript;

  // The compilation options applied throughout
  JS::CompileOptions& mCompileOptions;

  // Debug Metadata: Values managed for the benefit of the debugger when
  // inspecting code.
  //
  // For more details see CompilationAndEvaluation.h, and the comments on
  // UpdateDebugMetadata
  JS::Rooted<JS::Value> mDebuggerPrivateValue;
  JS::Rooted<JSScript*> mDebuggerIntroductionScript;

  // returned value forwarded when we have to interupt the execution eagerly
  // with mSkip.
  nsresult mRv;

  // Used to skip upcoming phases in case of a failure.  In such case the
  // result is carried by mRv.
  bool mSkip;

  // Should the result be serialized before being returned.
  bool mCoerceToString;

  // Encode the bytecode before it is being executed.
  bool mEncodeBytecode;

#ifdef DEBUG
  // Should we set the return value.
  bool mWantsReturnValue;

  bool mScriptUsed;
#endif

 private:
  // Compile a script contained in a SourceText.
  template <typename Unit>
  nsresult InternalCompile(JS::SourceText<Unit>& aSrcBuf);

  // Instantiate (on main-thread) a JS::Stencil generated by off-thread or
  // main-thread parsing or decoding.
  nsresult InstantiateStencil(RefPtr<JS::Stencil>&& aStencil,
                              JS::InstantiationStorage* aStorage = nullptr);

 public:
  // Enter compartment in which the code would be executed.  The JSContext
  // must come from an AutoEntryScript.
  //
  // The JS engine can associate metadata for the debugger with scripts at
  // compile time. The optional last arguments here cover that metadata.
  JSExecutionContext(
      JSContext* aCx, JS::Handle<JSObject*> aGlobal,
      JS::CompileOptions& aCompileOptions,
      JS::Handle<JS::Value> aDebuggerPrivateValue = JS::UndefinedHandleValue,
      JS::Handle<JSScript*> aDebuggerIntroductionScript = nullptr);

  JSExecutionContext(const JSExecutionContext&) = delete;
  JSExecutionContext(JSExecutionContext&&) = delete;

  ~JSExecutionContext() {
    // This flag is reset when the returned value is extracted.
    MOZ_ASSERT_IF(!mSkip, !mWantsReturnValue);

    // If encoding was started we expect the script to have been
    // used when ending the encoding.
    MOZ_ASSERT_IF(mEncodeBytecode && mScript && mRv == NS_OK, mScriptUsed);
  }

  // The returned value would be converted to a string if the
  // |aCoerceToString| is flag set.
  JSExecutionContext& SetCoerceToString(bool aCoerceToString) {
    mCoerceToString = aCoerceToString;
    return *this;
  }

  // When set, this flag records and encodes the bytecode as soon as it is
  // being compiled, and before it is being executed. The bytecode can then be
  // requested by using |JS::FinishIncrementalEncoding| with the mutable
  // handle |aScript| argument of |CompileAndExec| or |JoinAndExec|.
  JSExecutionContext& SetEncodeBytecode(bool aEncodeBytecode) {
    mEncodeBytecode = aEncodeBytecode;
    return *this;
  }

  // After getting a notification that an off-thread compile/decode finished,
  // this function will take the result of the off-thread operation and move it
  // to the main thread.
  [[nodiscard]] nsresult JoinOffThread(ScriptLoadContext* aContext);

  // Compile a script contained in a SourceText.
  nsresult Compile(JS::SourceText<char16_t>& aSrcBuf);
  nsresult Compile(JS::SourceText<mozilla::Utf8Unit>& aSrcBuf);

  // Compile a script contained in a string.
  nsresult Compile(const nsAString& aScript);

  // Decode a script contained in a buffer.
  nsresult Decode(const JS::TranscodeRange& aBytecodeBuf);

  // Get a successfully compiled script.
  JSScript* GetScript();

  // Get the compiled script if present, or nullptr.
  JSScript* MaybeGetScript();

  // Execute the compiled script and ignore the return value.
  [[nodiscard]] nsresult ExecScript();

  // Execute the compiled script a get the return value.
  //
  // Copy the returned value into the mutable handle argument. In case of a
  // evaluation failure either during the execution or the conversion of the
  // result to a string, the nsresult is be set to the corresponding result
  // code and the mutable handle argument remains unchanged.
  //
  // The value returned in the mutable handle argument is part of the
  // compartment given as argument to the JSExecutionContext constructor. If the
  // caller is in a different compartment, then the out-param value should be
  // wrapped by calling |JS_WrapValue|.
  [[nodiscard]] nsresult ExecScript(JS::MutableHandle<JS::Value> aRetValue);
};
}  // namespace dom
}  // namespace mozilla

#endif /* DOM_BASE_JSEXECUTIONCONTEXT_H_ */