Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/src/frontend/TryEmitter.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: set ts=8 sts=4 et sw=4 tw=99:
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_TryEmitter_h
8
#define frontend_TryEmitter_h
9
10
#include "mozilla/Attributes.h"
11
#include "mozilla/Maybe.h"
12
13
#include <stddef.h>
14
#include <stdint.h>
15
16
#include "frontend/BytecodeControlStructures.h"
17
#include "frontend/JumpList.h"
18
#include "frontend/TDZCheckCache.h"
19
20
namespace js {
21
namespace frontend {
22
23
struct BytecodeEmitter;
24
25
// Class for emitting bytecode for blocks like try-catch-finally.
26
//
27
// Usage: (check for the return value is omitted for simplicity)
28
//
29
//   `try { try_block } catch (ex) { catch_block }`
30
//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
31
//                         TryEmitter::ControlKind::Syntactic);
32
//     tryCatch.emitTry();
33
//     emit(try_block);
34
//     tryCatch.emitCatch();
35
//     emit(ex and catch_block); // use JSOP_EXCEPTION to get exception
36
//     tryCatch.emitEnd();
37
//
38
//   `try { try_block } finally { finally_block }`
39
//     TryEmitter tryCatch(this, TryEmitter::Kind::TryFinally,
40
//                         TryEmitter::ControlKind::Syntactic);
41
//     tryCatch.emitTry();
42
//     emit(try_block);
43
//     // finally_pos: The "{" character's position in the source code text.
44
//     tryCatch.emitFinally(Some(finally_pos));
45
//     emit(finally_block);
46
//     tryCatch.emitEnd();
47
//
48
//   `try { try_block } catch (ex) {catch_block} finally { finally_block }`
49
//     TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
50
//                         TryEmitter::ControlKind::Syntactic);
51
//     tryCatch.emitTry();
52
//     emit(try_block);
53
//     tryCatch.emitCatch();
54
//     emit(ex and catch_block);
55
//     tryCatch.emitFinally(Some(finally_pos));
56
//     emit(finally_block);
57
//     tryCatch.emitEnd();
58
//
59
class MOZ_STACK_CLASS TryEmitter
60
{
61
  public:
62
    enum class Kind {
63
        TryCatch,
64
        TryCatchFinally,
65
        TryFinally
66
    };
67
68
    // Syntactic try-catch-finally and internally used non-syntactic
69
    // try-catch-finally behave differently for 2 points.
70
    //
71
    // The first one is whether TryFinallyControl is used or not.
72
    // See the comment for `controlInfo_`.
73
    //
74
    // The second one is whether the catch and finally blocks handle the frame's
75
    // return value.  For syntactic try-catch-finally, the bytecode marked with
76
    // "*" are emitted to clear return value with `undefined` before the catch
77
    // block and the finally block, and also to save/restore the return value
78
    // before/after the finally block.
79
    //
80
    //     JSOP_TRY
81
    //
82
    //     try_body...
83
    //
84
    //     JSOP_GOSUB finally
85
    //     JSOP_JUMPTARGET
86
    //     JSOP_GOTO end:
87
    //
88
    //   catch:
89
    //     JSOP_JUMPTARGET
90
    //   * JSOP_UNDEFINED
91
    //   * JSOP_SETRVAL
92
    //
93
    //     catch_body...
94
    //
95
    //     JSOP_GOSUB finally
96
    //     JSOP_JUMPTARGET
97
    //     JSOP_GOTO end
98
    //
99
    //   finally:
100
    //     JSOP_JUMPTARGET
101
    //   * JSOP_GETRVAL
102
    //   * JSOP_UNDEFINED
103
    //   * JSOP_SETRVAL
104
    //
105
    //     finally_body...
106
    //
107
    //   * JSOP_SETRVAL
108
    //     JSOP_NOP
109
    //
110
    //   end:
111
    //     JSOP_JUMPTARGET
112
    //
113
    // For syntactic try-catch-finally, Syntactic should be used.
114
    // For non-syntactic try-catch-finally, NonSyntactic should be used.
115
    enum class ControlKind {
116
        Syntactic,
117
        NonSyntactic
118
    };
119
120
  private:
121
    BytecodeEmitter* bce_;
122
    Kind kind_;
123
    ControlKind controlKind_;
124
125
    // Track jumps-over-catches and gosubs-to-finally for later fixup.
126
    //
127
    // When a finally block is active, non-local jumps (including
128
    // jumps-over-catches) result in a GOSUB being written into the bytecode
129
    // stream and fixed-up later.
130
    //
131
    // For non-syntactic try-catch-finally, all that handling is skipped.
132
    // The non-syntactic try-catch-finally must:
133
    //   * have only one catch block
134
    //   * have JSOP_GOTO at the end of catch-block
135
    //   * have no non-local-jump
136
    //   * don't use finally block for normal completion of try-block and
137
    //     catch-block
138
    //
139
    // Additionally, a finally block may be emitted for non-syntactic
140
    // try-catch-finally, even if the kind is TryCatch, because GOSUBs are not
141
    // emitted.
142
    mozilla::Maybe<TryFinallyControl> controlInfo_;
143
144
    // The stack depth before emitting JSOP_TRY.
145
    int depth_;
146
147
    // The source note index for SRC_TRY.
148
    unsigned noteIndex_;
149
150
    // The offset after JSOP_TRY.
151
    ptrdiff_t tryStart_;
152
153
    // JSOP_JUMPTARGET after the entire try-catch-finally block.
154
    JumpList catchAndFinallyJump_;
155
156
    // The offset of JSOP_GOTO at the end of the try block.
157
    JumpTarget tryEnd_;
158
159
    // The offset of JSOP_JUMPTARGET at the beginning of the finally block.
160
    JumpTarget finallyStart_;
161
162
#ifdef DEBUG
163
    // The state of this emitter.
164
    //
165
    // +-------+ emitTry +-----+   emitCatch +-------+      emitEnd  +-----+
166
    // | Start |-------->| Try |-+---------->| Catch |-+->+--------->| End |
167
    // +-------+         +-----+ |           +-------+ |  ^          +-----+
168
    //                           |                     |  |
169
    //                           |  +------------------+  +----+
170
    //                           |  |                          |
171
    //                           |  v emitFinally +---------+  |
172
    //                           +->+------------>| Finally |--+
173
    //                                            +---------+
174
    enum class State {
175
        // The initial state.
176
        Start,
177
178
        // After calling emitTry.
179
        Try,
180
181
        // After calling emitCatch.
182
        Catch,
183
184
        // After calling emitFinally.
185
        Finally,
186
187
        // After calling emitEnd.
188
        End
189
    };
190
    State state_;
191
#endif
192
193
70
    bool hasCatch() const {
194
70
        return kind_ == Kind::TryCatch || kind_ == Kind::TryCatchFinally;
195
70
    }
196
262
    bool hasFinally() const {
197
262
        return kind_ == Kind::TryCatchFinally || kind_ == Kind::TryFinally;
198
262
    }
199
200
  public:
201
    TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind);
202
203
    // Emits JSOP_GOTO to the end of try-catch-finally.
204
    // Used in `yield*`.
205
    MOZ_MUST_USE bool emitJumpOverCatchAndFinally();
206
207
    MOZ_MUST_USE bool emitTry();
208
    MOZ_MUST_USE bool emitCatch();
209
210
    // If `finallyPos` is specified, it's an offset of the finally block's
211
    // "{" character in the source code text, to improve line:column number in
212
    // the error reporting.
213
    // For non-syntactic try-catch-finally, `finallyPos` can be omitted.
214
    MOZ_MUST_USE bool emitFinally(const mozilla::Maybe<uint32_t>& finallyPos = mozilla::Nothing());
215
216
    MOZ_MUST_USE bool emitEnd();
217
218
  private:
219
    MOZ_MUST_USE bool emitTryEnd();
220
    MOZ_MUST_USE bool emitCatchEnd();
221
    MOZ_MUST_USE bool emitFinallyEnd();
222
};
223
224
} /* namespace frontend */
225
} /* namespace js */
226
227
#endif /* frontend_TryEmitter_h */