Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / BytecodeSection.h
blob0e7ed3d44756e98dfc4d0c8def4a6aba65809805
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef frontend_BytecodeSection_h
8 #define frontend_BytecodeSection_h
10 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS
11 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include "mozilla/Span.h" // mozilla::Span
14 #include <stddef.h> // ptrdiff_t, size_t
15 #include <stdint.h> // uint16_t, int32_t, uint32_t
17 #include "frontend/AbstractScopePtr.h" // AbstractScopePtr, ScopeIndex
18 #include "frontend/BytecodeOffset.h" // BytecodeOffset
19 #include "frontend/CompilationStencil.h" // CompilationStencil, CompilationGCOutput, CompilationAtomCache
20 #include "frontend/FrontendContext.h" // FrontendContext
21 #include "frontend/JumpList.h" // JumpTarget
22 #include "frontend/NameCollections.h" // AtomIndexMap, PooledMapPtr
23 #include "frontend/ParseNode.h" // BigIntLiteral
24 #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex, ParserAtom
25 #include "frontend/SourceNotes.h" // SrcNote
26 #include "frontend/Stencil.h" // Stencils
27 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin
28 #include "js/TypeDecls.h" // jsbytecode, JSContext
29 #include "js/Vector.h" // Vector
30 #include "vm/SharedStencil.h" // TryNote, ScopeNote, GCThingIndex
31 #include "vm/StencilEnums.h" // TryNoteKind
33 namespace js {
34 namespace frontend {
36 class FunctionBox;
38 struct MOZ_STACK_CLASS GCThingList {
39 // The BCE accumulates TaggedScriptThingIndex items so use a vector type. We
40 // reserve some stack slots to avoid allocating for most small scripts.
41 using ScriptThingsStackVector = Vector<TaggedScriptThingIndex, 8>;
43 CompilationState& compilationState;
44 ScriptThingsStackVector vector;
46 // Index of the first scope in the vector.
47 mozilla::Maybe<GCThingIndex> firstScopeIndex;
49 explicit GCThingList(FrontendContext* fc, CompilationState& compilationState)
50 : compilationState(compilationState), vector(fc) {}
52 [[nodiscard]] bool append(TaggedParserAtomIndex atom,
53 ParserAtom::Atomize atomize, GCThingIndex* index) {
54 *index = GCThingIndex(vector.length());
55 compilationState.parserAtoms.markUsedByStencil(atom, atomize);
56 if (!vector.emplaceBack(atom)) {
57 return false;
59 return true;
61 [[nodiscard]] bool append(ScopeIndex scope, GCThingIndex* index) {
62 *index = GCThingIndex(vector.length());
63 if (!vector.emplaceBack(scope)) {
64 return false;
66 if (!firstScopeIndex) {
67 firstScopeIndex.emplace(*index);
69 return true;
71 [[nodiscard]] bool append(BigIntLiteral* literal, GCThingIndex* index) {
72 *index = GCThingIndex(vector.length());
73 if (!vector.emplaceBack(literal->index())) {
74 return false;
76 return true;
78 [[nodiscard]] bool append(RegExpLiteral* literal, GCThingIndex* index) {
79 *index = GCThingIndex(vector.length());
80 if (!vector.emplaceBack(literal->index())) {
81 return false;
83 return true;
85 [[nodiscard]] bool append(ObjLiteralIndex objlit, GCThingIndex* index) {
86 *index = GCThingIndex(vector.length());
87 if (!vector.emplaceBack(objlit)) {
88 return false;
90 return true;
92 [[nodiscard]] bool append(FunctionBox* funbox, GCThingIndex* index);
94 [[nodiscard]] bool appendEmptyGlobalScope(GCThingIndex* index) {
95 *index = GCThingIndex(vector.length());
96 EmptyGlobalScopeType emptyGlobalScope;
97 if (!vector.emplaceBack(emptyGlobalScope)) {
98 return false;
100 if (!firstScopeIndex) {
101 firstScopeIndex.emplace(*index);
103 return true;
106 uint32_t length() const { return vector.length(); }
108 const ScriptThingsStackVector& objects() { return vector; }
110 AbstractScopePtr getScope(size_t index) const;
112 // Index of scope within CompilationStencil or Nothing is the scope is
113 // EmptyGlobalScopeType.
114 mozilla::Maybe<ScopeIndex> getScopeIndex(size_t index) const;
116 TaggedParserAtomIndex getAtom(size_t index) const;
118 AbstractScopePtr firstScope() const {
119 MOZ_ASSERT(firstScopeIndex.isSome());
120 return getScope(*firstScopeIndex);
124 [[nodiscard]] bool EmitScriptThingsVector(
125 JSContext* cx, const CompilationAtomCache& atomCache,
126 const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
127 mozilla::Span<const TaggedScriptThingIndex> things,
128 mozilla::Span<JS::GCCellPtr> output);
130 struct CGTryNoteList {
131 Vector<TryNote, 0> list;
132 explicit CGTryNoteList(FrontendContext* fc) : list(fc) {}
134 [[nodiscard]] bool append(TryNoteKind kind, uint32_t stackDepth,
135 BytecodeOffset start, BytecodeOffset end);
136 mozilla::Span<const TryNote> span() const {
137 return {list.begin(), list.length()};
139 size_t length() const { return list.length(); }
142 struct CGScopeNoteList {
143 Vector<ScopeNote, 0> list;
144 explicit CGScopeNoteList(FrontendContext* fc) : list(fc) {}
146 [[nodiscard]] bool append(GCThingIndex scopeIndex, BytecodeOffset offset,
147 uint32_t parent);
148 void recordEnd(uint32_t index, BytecodeOffset offset);
149 void recordEndFunctionBodyVar(uint32_t index);
150 mozilla::Span<const ScopeNote> span() const {
151 return {list.begin(), list.length()};
153 size_t length() const { return list.length(); }
155 private:
156 void recordEndImpl(uint32_t index, uint32_t offset);
159 struct CGResumeOffsetList {
160 Vector<uint32_t, 0> list;
161 explicit CGResumeOffsetList(FrontendContext* fc) : list(fc) {}
163 [[nodiscard]] bool append(uint32_t offset) { return list.append(offset); }
164 mozilla::Span<const uint32_t> span() const {
165 return {list.begin(), list.length()};
167 size_t length() const { return list.length(); }
170 static constexpr size_t MaxBytecodeLength = INT32_MAX;
171 static constexpr size_t MaxSrcNotesLength = INT32_MAX;
173 // Have a few inline elements, so as to avoid heap allocation for tiny
174 // sequences. See bug 1390526.
175 typedef Vector<jsbytecode, 64> BytecodeVector;
176 typedef Vector<js::SrcNote, 64> SrcNotesVector;
178 // Bytecode and all data directly associated with specific opcode/index inside
179 // bytecode is stored in this class.
180 class BytecodeSection {
181 public:
182 BytecodeSection(FrontendContext* fc, uint32_t lineNum,
183 JS::LimitedColumnNumberOneOrigin column);
185 // ---- Bytecode ----
187 BytecodeVector& code() { return code_; }
188 const BytecodeVector& code() const { return code_; }
190 jsbytecode* code(BytecodeOffset offset) {
191 return code_.begin() + offset.value();
193 BytecodeOffset offset() const {
194 return BytecodeOffset(code_.end() - code_.begin());
197 // ---- Source notes ----
199 SrcNotesVector& notes() { return notes_; }
200 const SrcNotesVector& notes() const { return notes_; }
202 BytecodeOffset lastNoteOffset() const { return lastNoteOffset_; }
203 void setLastNoteOffset(BytecodeOffset offset) { lastNoteOffset_ = offset; }
205 // ---- Jump ----
207 BytecodeOffset lastTargetOffset() const { return lastTarget_.offset; }
208 void setLastTargetOffset(BytecodeOffset offset) {
209 lastTarget_.offset = offset;
212 // ---- Stack ----
214 int32_t stackDepth() const { return stackDepth_; }
215 void setStackDepth(int32_t depth) { stackDepth_ = depth; }
217 uint32_t maxStackDepth() const { return maxStackDepth_; }
219 void updateDepth(JSOp op, BytecodeOffset target);
221 // ---- Try notes ----
223 CGTryNoteList& tryNoteList() { return tryNoteList_; };
224 const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
226 // ---- Scope ----
228 CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
229 const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
231 // ---- Generator ----
233 CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
234 const CGResumeOffsetList& resumeOffsetList() const {
235 return resumeOffsetList_;
238 uint32_t numYields() const { return numYields_; }
239 void addNumYields() { numYields_++; }
241 // ---- Line and column ----
243 uint32_t currentLine() const { return currentLine_; }
244 JS::LimitedColumnNumberOneOrigin lastColumn() const { return lastColumn_; }
245 void setCurrentLine(uint32_t line, uint32_t sourceOffset) {
246 currentLine_ = line;
247 lastColumn_ = JS::LimitedColumnNumberOneOrigin();
248 lastSourceOffset_ = sourceOffset;
251 void setLastColumn(JS::LimitedColumnNumberOneOrigin column, uint32_t offset) {
252 lastColumn_ = column;
253 lastSourceOffset_ = offset;
256 void updateSeparatorPosition() {
257 lastSeparatorCodeOffset_ = code().length();
258 lastSeparatorSourceOffset_ = lastSourceOffset_;
259 lastSeparatorLine_ = currentLine_;
260 lastSeparatorColumn_ = lastColumn_;
263 void updateSeparatorPositionIfPresent() {
264 if (lastSeparatorCodeOffset_ == code().length()) {
265 lastSeparatorSourceOffset_ = lastSourceOffset_;
266 lastSeparatorLine_ = currentLine_;
267 lastSeparatorColumn_ = lastColumn_;
271 bool isDuplicateLocation() const {
272 return lastSeparatorLine_ == currentLine_ &&
273 lastSeparatorColumn_ == lastColumn_;
276 bool atSeparator(uint32_t offset) const {
277 return lastSeparatorSourceOffset_ == offset;
280 // ---- JIT ----
282 uint32_t numICEntries() const { return numICEntries_; }
283 void incrementNumICEntries() {
284 MOZ_ASSERT(numICEntries_ != UINT32_MAX, "Shouldn't overflow");
285 numICEntries_++;
287 void setNumICEntries(uint32_t entries) { numICEntries_ = entries; }
289 private:
290 // ---- Bytecode ----
292 // Bytecode.
293 BytecodeVector code_;
295 // ---- Source notes ----
297 // Source notes
298 SrcNotesVector notes_;
300 // Code offset for last source note
301 BytecodeOffset lastNoteOffset_;
303 // ---- Jump ----
305 // Last jump target emitted.
306 JumpTarget lastTarget_;
308 // ---- Stack ----
310 // Maximum number of expression stack slots so far.
311 uint32_t maxStackDepth_ = 0;
313 // Current stack depth in script frame.
314 int32_t stackDepth_ = 0;
316 // ---- Try notes ----
318 // List of emitted try notes.
319 CGTryNoteList tryNoteList_;
321 // ---- Scope ----
323 // List of emitted block scope notes.
324 CGScopeNoteList scopeNoteList_;
326 // ---- Generator ----
328 // Certain ops (yield, await) have an entry in the script's resumeOffsets
329 // list. This can be used to map from the op's resumeIndex to the bytecode
330 // offset of the next pc. This indirection makes it easy to resume in the JIT
331 // (because BaselineScript stores a resumeIndex => native code array).
332 CGResumeOffsetList resumeOffsetList_;
334 // Number of yield instructions emitted. Does not include JSOp::Await.
335 uint32_t numYields_ = 0;
337 // ---- Line and column ----
339 // Line number for srcnotes.
341 // WARNING: If this becomes out of sync with already-emitted srcnotes,
342 // we can get undefined behavior.
343 uint32_t currentLine_;
345 // Column index in UTF-16 code units on currentLine_ of last
346 // SrcNoteType::ColSpan-annotated opcode.
348 // WARNING: If this becomes out of sync with already-emitted srcnotes,
349 // we can get undefined behavior.
350 JS::LimitedColumnNumberOneOrigin lastColumn_;
352 // The last code unit used for srcnotes.
353 uint32_t lastSourceOffset_ = 0;
355 // The offset, line and column numbers of the last opcode for the
356 // breakpoint for step execution.
357 uint32_t lastSeparatorCodeOffset_ = 0;
358 uint32_t lastSeparatorSourceOffset_ = 0;
359 uint32_t lastSeparatorLine_ = 0;
360 JS::LimitedColumnNumberOneOrigin lastSeparatorColumn_;
362 // ---- JIT ----
364 // Number of ICEntries in the script. There's one ICEntry for each JOF_IC op
365 // and, if the script is a function, for |this| and each formal argument.
366 uint32_t numICEntries_ = 0;
369 // Data that is not directly associated with specific opcode/index inside
370 // bytecode, but referred from bytecode is stored in this class.
371 class PerScriptData {
372 public:
373 PerScriptData(FrontendContext* fc,
374 frontend::CompilationState& compilationState);
376 [[nodiscard]] bool init(FrontendContext* fc);
378 GCThingList& gcThingList() { return gcThingList_; }
379 const GCThingList& gcThingList() const { return gcThingList_; }
381 PooledMapPtr<AtomIndexMap>& atomIndices() { return atomIndices_; }
382 const PooledMapPtr<AtomIndexMap>& atomIndices() const { return atomIndices_; }
384 private:
385 // List of emitted scopes/objects/bigints.
386 GCThingList gcThingList_;
388 // Map from atom to index.
389 PooledMapPtr<AtomIndexMap> atomIndices_;
392 } /* namespace frontend */
393 } /* namespace js */
395 #endif /* frontend_BytecodeSection_h */