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
// head:
98
// JSOp::LoopHead
99
// {loop condition/body}
100
//
101
// continueTarget:
102
// {loop update if present}
103
//
104
// # Loop end, backward jump
105
// JSOp::Goto/JSOp::IfNe head
106
//
107
// breakTarget:
108
109
// The bytecode offset of JSOp::LoopHead.
110
JumpTarget head_;
111
112
// Stack depth when this loop was pushed on the control stack.
113
int32_t stackDepth_;
114
115
// The loop nesting depth. Used as a hint to Ion.
116
uint32_t loopDepth_;
117
118
public:
119
// Offset of the last continue in the loop.
120
JumpList continues;
121
122
LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
123
124
BytecodeOffset headOffset() const { return head_.offset; }
125
126
MOZ_MUST_USE bool emitContinueTarget(BytecodeEmitter* bce);
127
128
// `nextPos` is the offset in the source code for the character that
129
// corresponds to the next instruction after JSOp::LoopHead.
130
// Can be Nothing() if not available.
131
MOZ_MUST_USE bool emitLoopHead(BytecodeEmitter* bce,
132
const mozilla::Maybe<uint32_t>& nextPos);
133
134
MOZ_MUST_USE bool emitLoopEnd(BytecodeEmitter* bce, JSOp op,
135
JSTryNoteKind tryNoteKind);
136
};
137
template <>
138
inline bool NestableControl::is<LoopControl>() const {
139
return StatementKindIsLoop(kind_);
140
}
141
142
class TryFinallyControl : public NestableControl {
143
bool emittingSubroutine_;
144
145
public:
146
// The subroutine when emitting a finally block.
147
JumpList gosubs;
148
149
TryFinallyControl(BytecodeEmitter* bce, StatementKind kind);
150
151
void setEmittingSubroutine() { emittingSubroutine_ = true; }
152
153
bool emittingSubroutine() const { return emittingSubroutine_; }
154
};
155
template <>
156
inline bool NestableControl::is<TryFinallyControl>() const {
157
return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
158
}
159
160
} /* namespace frontend */
161
} /* namespace js */
162
163
#endif /* frontend_BytecodeControlStructures_h */