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
#include "frontend/BytecodeControlStructures.h"
8
9
#include "frontend/BytecodeEmitter.h" // BytecodeEmitter
10
#include "frontend/EmitterScope.h" // EmitterScope
11
#include "frontend/SourceNotes.h" // SRC_*
12
#include "vm/Opcodes.h" // JSOP_*
13
14
using namespace js;
15
using namespace js::frontend;
16
17
using mozilla::Maybe;
18
19
NestableControl::NestableControl(BytecodeEmitter* bce, StatementKind kind)
20
: Nestable<NestableControl>(&bce->innermostNestableControl),
21
kind_(kind),
22
emitterScope_(bce->innermostEmitterScopeNoCheck()) {}
23
24
BreakableControl::BreakableControl(BytecodeEmitter* bce, StatementKind kind)
25
: NestableControl(bce, kind) {
26
MOZ_ASSERT(is<BreakableControl>());
27
}
28
29
bool BreakableControl::patchBreaks(BytecodeEmitter* bce) {
30
return bce->emitJumpTargetAndPatch(breaks);
31
}
32
33
LabelControl::LabelControl(BytecodeEmitter* bce, JSAtom* label,
34
BytecodeOffset startOffset)
35
: BreakableControl(bce, StatementKind::Label),
36
label_(bce->cx, label),
37
startOffset_(startOffset) {}
38
39
LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
40
: BreakableControl(bce, loopKind), tdzCache_(bce) {
41
MOZ_ASSERT(is<LoopControl>());
42
43
LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
44
45
stackDepth_ = bce->bytecodeSection().stackDepth();
46
loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
47
48
int loopSlots;
49
if (loopKind == StatementKind::Spread) {
50
// The iterator next method, the iterator, the result array, and
51
// the current array index are on the stack.
52
loopSlots = 4;
53
} else if (loopKind == StatementKind::ForOfLoop) {
54
// The iterator next method, the iterator, and the current value
55
// are on the stack.
56
loopSlots = 3;
57
} else if (loopKind == StatementKind::ForInLoop) {
58
// The iterator and the current value are on the stack.
59
loopSlots = 2;
60
} else {
61
// No additional loop values are on the stack.
62
loopSlots = 0;
63
}
64
65
MOZ_ASSERT(loopSlots <= stackDepth_);
66
67
if (enclosingLoop) {
68
canIonOsr_ = (enclosingLoop->canIonOsr_ &&
69
stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
70
} else {
71
canIonOsr_ = stackDepth_ == loopSlots;
72
}
73
}
74
75
bool LoopControl::emitContinueTarget(BytecodeEmitter* bce) {
76
if (!bce->emitJumpTarget(&continueTarget_)) {
77
return false;
78
}
79
return true;
80
}
81
82
bool LoopControl::emitSpecialBreakForDone(BytecodeEmitter* bce) {
83
// This doesn't pop stack values, nor handle any other controls.
84
// Should be called on the toplevel of the loop.
85
MOZ_ASSERT(bce->bytecodeSection().stackDepth() == stackDepth_);
86
MOZ_ASSERT(bce->innermostNestableControl == this);
87
88
if (!bce->newSrcNote(SRC_BREAK)) {
89
return false;
90
}
91
if (!bce->emitJump(JSOP_GOTO, &breaks)) {
92
return false;
93
}
94
95
return true;
96
}
97
98
bool LoopControl::emitEntryJump(BytecodeEmitter* bce) {
99
if (!bce->emitJump(JSOP_GOTO, &entryJump_)) {
100
return false;
101
}
102
return true;
103
}
104
105
bool LoopControl::emitLoopHead(BytecodeEmitter* bce,
106
const Maybe<uint32_t>& nextPos) {
107
if (nextPos) {
108
if (!bce->updateSourceCoordNotes(*nextPos)) {
109
return false;
110
}
111
}
112
113
head_ = {bce->bytecodeSection().offset()};
114
BytecodeOffset off;
115
if (!bce->emitJumpTargetOp(JSOP_LOOPHEAD, &off)) {
116
return false;
117
}
118
119
return true;
120
}
121
122
bool LoopControl::emitLoopEntry(BytecodeEmitter* bce,
123
const Maybe<uint32_t>& nextPos) {
124
if (nextPos) {
125
if (!bce->updateSourceCoordNotes(*nextPos)) {
126
return false;
127
}
128
}
129
130
JumpTarget entry = {bce->bytecodeSection().offset()};
131
bce->patchJumpsToTarget(entryJump_, entry);
132
133
MOZ_ASSERT(loopDepth_ > 0);
134
135
BytecodeOffset off;
136
if (!bce->emitJumpTargetOp(JSOP_LOOPENTRY, &off)) {
137
return false;
138
}
139
SetLoopEntryDepthHintAndFlags(bce->bytecodeSection().code(off), loopDepth_,
140
canIonOsr_);
141
142
return true;
143
}
144
145
bool LoopControl::emitLoopEnd(BytecodeEmitter* bce, JSOp op) {
146
JumpList beq;
147
if (!bce->emitBackwardJump(op, head_, &beq, &breakTarget_)) {
148
return false;
149
}
150
151
loopEndOffset_ = beq.offset;
152
153
return true;
154
}
155
156
bool LoopControl::patchBreaksAndContinues(BytecodeEmitter* bce) {
157
MOZ_ASSERT(continueTarget_.offset.valid());
158
if (!patchBreaks(bce)) {
159
return false;
160
}
161
bce->patchJumpsToTarget(continues, continueTarget_);
162
return true;
163
}
164
165
TryFinallyControl::TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
166
: NestableControl(bce, kind), emittingSubroutine_(false) {
167
MOZ_ASSERT(is<TryFinallyControl>());
168
}