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
|
/* -*- 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/. */
#include "frontend/BytecodeControlStructures.h"
#include "frontend/BytecodeEmitter.h" // BytecodeEmitter
#include "frontend/EmitterScope.h" // EmitterScope
#include "vm/Opcodes.h" // JSOp
using namespace js;
using namespace js::frontend;
using mozilla::Maybe;
NestableControl::NestableControl(BytecodeEmitter* bce, StatementKind kind)
: Nestable<NestableControl>(&bce->innermostNestableControl),
kind_(kind),
emitterScope_(bce->innermostEmitterScopeNoCheck()) {}
BreakableControl::BreakableControl(BytecodeEmitter* bce, StatementKind kind)
: NestableControl(bce, kind) {
MOZ_ASSERT(is<BreakableControl>());
}
bool BreakableControl::patchBreaks(BytecodeEmitter* bce) {
return bce->emitJumpTargetAndPatch(breaks);
}
LabelControl::LabelControl(BytecodeEmitter* bce, const ParserAtom* label,
BytecodeOffset startOffset)
: BreakableControl(bce, StatementKind::Label),
label_(label),
startOffset_(startOffset) {}
LoopControl::LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
: BreakableControl(bce, loopKind), tdzCache_(bce) {
MOZ_ASSERT(is<LoopControl>());
LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
stackDepth_ = bce->bytecodeSection().stackDepth();
loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
}
bool LoopControl::emitContinueTarget(BytecodeEmitter* bce) {
// Note: this is always called after emitting the loop body so we must have
// emitted all 'continues' by now.
return bce->emitJumpTargetAndPatch(continues);
}
bool LoopControl::emitLoopHead(BytecodeEmitter* bce,
const Maybe<uint32_t>& nextPos) {
// Insert a Nop if needed to ensure the script does not start with a
// JSOp::LoopHead. This avoids JIT issues with prologue code + try notes
// or OSR. See bug 1602390 and bug 1602681.
if (bce->bytecodeSection().offset().toUint32() == 0) {
if (!bce->emit1(JSOp::Nop)) {
return false;
}
}
if (nextPos) {
if (!bce->updateSourceCoordNotes(*nextPos)) {
return false;
}
}
MOZ_ASSERT(loopDepth_ > 0);
head_ = {bce->bytecodeSection().offset()};
BytecodeOffset off;
if (!bce->emitJumpTargetOp(JSOp::LoopHead, &off)) {
return false;
}
SetLoopHeadDepthHint(bce->bytecodeSection().code(off), loopDepth_);
return true;
}
bool LoopControl::emitLoopEnd(BytecodeEmitter* bce, JSOp op,
TryNoteKind tryNoteKind) {
JumpList jump;
if (!bce->emitJumpNoFallthrough(op, &jump)) {
return false;
}
bce->patchJumpsToTarget(jump, head_);
// Create a fallthrough for closing iterators, and as a target for break
// statements.
JumpTarget breakTarget;
if (!bce->emitJumpTarget(&breakTarget)) {
return false;
}
if (!patchBreaks(bce)) {
return false;
}
if (!bce->addTryNote(tryNoteKind, bce->bytecodeSection().stackDepth(),
headOffset(), breakTarget.offset)) {
return false;
}
return true;
}
TryFinallyControl::TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
: NestableControl(bce, kind), emittingSubroutine_(false) {
MOZ_ASSERT(is<TryFinallyControl>());
}
|