Source code

Revision control

Other Tools

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 frontend_BytecodeControlStructures_h
8
#define frontend_BytecodeControlStructures_h
9
10
#include "mozilla/Assertions.h" // MOZ_ASSERT
11
#include "mozilla/Attributes.h" // MOZ_MUST_USE
12
#include "mozilla/Maybe.h" // mozilla::Maybe
13
14
#include <stdint.h> // int32_t, uint32_t
15
16
#include "ds/Nestable.h" // Nestable
17
#include "frontend/BytecodeSection.h" // BytecodeOffset
18
#include "frontend/JumpList.h" // JumpList, JumpTarget
19
#include "frontend/SharedContext.h" // StatementKind, StatementKindIsLoop, StatementKindIsUnlabeledBreakTarget
20
#include "frontend/TDZCheckCache.h" // TDZCheckCache
21
#include "gc/Rooting.h" // RootedAtom, HandleAtom
22
#include "vm/StringType.h" // JSAtom
23
24
namespace js {
25
namespace frontend {
26
27
struct BytecodeEmitter;
28
class EmitterScope;
29
30
class NestableControl : public Nestable<NestableControl> {
31
StatementKind kind_;
32
33
// The innermost scope when this was pushed.
34
EmitterScope* emitterScope_;
35
36
protected:
37
NestableControl(BytecodeEmitter* bce, StatementKind kind);
38
39
public:
40
using Nestable<NestableControl>::enclosing;
41
using Nestable<NestableControl>::findNearest;
42
43
StatementKind kind() const { return kind_; }
44
45
EmitterScope* emitterScope() const { return emitterScope_; }
46
47
template <typename T>
48
bool is() const;
49
50
template <typename T>
51
T& as() {
52
MOZ_ASSERT(this->is<T>());
53
return static_cast<T&>(*this);
54
}
55
};
56
57
class BreakableControl : public NestableControl {
58
public:
59
// Offset of the last break.
60
JumpList breaks;
61
62
BreakableControl(BytecodeEmitter* bce, StatementKind kind);
63
64
MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce);
65
};
66
template <>
67
inline bool NestableControl::is<BreakableControl>() const {
68
return StatementKindIsUnlabeledBreakTarget(kind_) ||
69
kind_ == StatementKind::Label;
70
}
71
72
class LabelControl : public BreakableControl {
73
RootedAtom label_;
74
75
// The code offset when this was pushed. Used for effectfulness checking.
76
BytecodeOffset startOffset_;
77
78
public:
79
LabelControl(BytecodeEmitter* bce, JSAtom* label, BytecodeOffset startOffset);
80
81
HandleAtom label() const { return label_; }
82
83
BytecodeOffset startOffset() const { return startOffset_; }
84
};
85
template <>
86
inline bool NestableControl::is<LabelControl>() const {
87
return kind_ == StatementKind::Label;
88
}
89
90
class LoopControl : public BreakableControl {
91
// Loops' children are emitted in dominance order, so they can always
92
// have a TDZCheckCache.
93
TDZCheckCache tdzCache_;
94
95
// Here's the basic structure of a loop:
96
//
97
// # Entry jump
98
// JSOP_GOTO entry
99
//
100
// head:
101
// JSOP_LOOPHEAD
102
// {loop body after branch}
103
//
104
// entry:
105
// JSOP_ENTRY
106
// {loop body before branch}
107
//
108
// # Loop end, backward jump
109
// JSOP_GOTO/JSOP_IFNE head
110
//
111
// breakTarget:
112
//
113
// `continueTarget` can be placed in arbitrary place by calling
114
// `setContinueTarget` or `emitContinueTarget` (see comment above them for
115
// more details).
116
117
// The offset of backward jump at the end of loop.
118
BytecodeOffset loopEndOffset_ = BytecodeOffset::invalidOffset();
119
120
// The jump into JSOP_LOOPENTRY.
121
JumpList entryJump_;
122
123
// The bytecode offset of JSOP_LOOPHEAD.
124
JumpTarget head_;
125
126
// The target of break statement jumps.
127
JumpTarget breakTarget_;
128
129
// The target of continue statement jumps, e.g., the update portion of a
130
// for(;;) loop.
131
JumpTarget continueTarget_;
132
133
// Stack depth when this loop was pushed on the control stack.
134
int32_t stackDepth_;
135
136
// The loop nesting depth. Used as a hint to Ion.
137
uint32_t loopDepth_;
138
139
// Can we OSR into Ion from here? True unless there is non-loop state on the
140
// stack.
141
bool canIonOsr_;
142
143
public:
144
// Offset of the last continue in the loop.
145
JumpList continues;
146
147
LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
148
149
BytecodeOffset headOffset() const { return head_.offset; }
150
BytecodeOffset loopEndOffset() const { return loopEndOffset_; }
151
BytecodeOffset breakTargetOffset() const { return breakTarget_.offset; }
152
BytecodeOffset continueTargetOffset() const { return continueTarget_.offset; }
153
154
// The offset of the backward jump at the loop end from the loop's top, in
155
// case there was an entry jump.
156
BytecodeOffsetDiff loopEndOffsetFromEntryJump() const {
157
return loopEndOffset_ - entryJump_.offset;
158
}
159
160
// The offset of the backward jump at the loop end from the loop's top, in
161
// case there was no entry jump.
162
BytecodeOffsetDiff loopEndOffsetFromLoopHead() const {
163
return loopEndOffset_ - head_.offset;
164
}
165
166
// The offset of the continue target from the loop's top, in case there was
167
// no entry jump.
168
BytecodeOffsetDiff continueTargetOffsetFromLoopHead() const {
169
return continueTarget_.offset - head_.offset;
170
}
171
172
// A continue target can be specified by the following 2 ways:
173
// * Use the existing JUMPTARGET by calling `setContinueTarget` with
174
// the offset of the JUMPTARGET
175
// * Generate a new JUMPTARGETby calling `emitContinueTarget`
176
void setContinueTarget(BytecodeOffset offset) {
177
continueTarget_.offset = offset;
178
}
179
MOZ_MUST_USE bool emitContinueTarget(BytecodeEmitter* bce);
180
181
// Emit a jump to break target from the top level of the loop.
182
MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce);
183
184
MOZ_MUST_USE bool emitEntryJump(BytecodeEmitter* bce);
185
186
// `nextPos` is the offset in the source code for the character that
187
// corresponds to the next instruction after JSOP_LOOPHEAD.
188
// Can be Nothing() if not available.
189
MOZ_MUST_USE bool emitLoopHead(BytecodeEmitter* bce,
190
const mozilla::Maybe<uint32_t>& nextPos);
191
192
// `nextPos` is the offset in the source code for the character that
193
// corresponds to the next instruction after JSOP_LOOPENTRY.
194
// Can be Nothing() if not available.
195
MOZ_MUST_USE bool emitLoopEntry(BytecodeEmitter* bce,
196
const mozilla::Maybe<uint32_t>& nextPos);
197
198
MOZ_MUST_USE bool emitLoopEnd(BytecodeEmitter* bce, JSOp op);
199
MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce);
200
};
201
template <>
202
inline bool NestableControl::is<LoopControl>() const {
203
return StatementKindIsLoop(kind_);
204
}
205
206
class TryFinallyControl : public NestableControl {
207
bool emittingSubroutine_;
208
209
public:
210
// The subroutine when emitting a finally block.
211
JumpList gosubs;
212
213
TryFinallyControl(BytecodeEmitter* bce, StatementKind kind);
214
215
void setEmittingSubroutine() { emittingSubroutine_ = true; }
216
217
bool emittingSubroutine() const { return emittingSubroutine_; }
218
};
219
template <>
220
inline bool NestableControl::is<TryFinallyControl>() const {
221
return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
222
}
223
224
} /* namespace frontend */
225
} /* namespace js */
226
227
#endif /* frontend_BytecodeControlStructures_h */