summaryrefslogtreecommitdiff
path: root/js/src/frontend/TryEmitter.h
blob: c852e3556d59f7231210cd0fc983ad9a6af0b6b9 (plain)
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
112
113
114
115
116
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * 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/. */

#ifndef frontend_TryEmitter_h
#define frontend_TryEmitter_h

#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"

#include <stddef.h>
#include <stdint.h>

#include "frontend/BytecodeControlStructures.h"
#include "frontend/JumpList.h"
#include "frontend/TDZCheckCache.h"

namespace js {
namespace frontend {

struct BytecodeEmitter;

class MOZ_STACK_CLASS TryEmitter
{
  public:
    enum Kind {
        TryCatch,
        TryCatchFinally,
        TryFinally
    };
    enum ShouldUseRetVal {
        UseRetVal,
        DontUseRetVal
    };
    enum ShouldUseControl {
        UseControl,
        DontUseControl,
    };

  private:
    BytecodeEmitter* bce_;
    Kind kind_;
    ShouldUseRetVal retValKind_;

    // Track jumps-over-catches and gosubs-to-finally for later fixup.
    //
    // When a finally block is active, non-local jumps (including
    // jumps-over-catches) result in a GOSUB being written into the bytecode
    // stream and fixed-up later.
    //
    // If ShouldUseControl is DontUseControl, all that handling is skipped.
    // DontUseControl is used by yield* and the internal try-catch around
    // IteratorClose. These internal uses must:
    //   * have only one catch block
    //   * have no catch guard
    //   * have JSOP_GOTO at the end of catch-block
    //   * have no non-local-jump
    //   * don't use finally block for normal completion of try-block and
    //     catch-block
    //
    // Additionally, a finally block may be emitted when ShouldUseControl is
    // DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
    // because GOSUBs are not emitted. This internal use shares the
    // requirements as above.
    Maybe<TryFinallyControl> controlInfo_;

    int depth_;
    unsigned noteIndex_;
    ptrdiff_t tryStart_;
    JumpList catchAndFinallyJump_;
    JumpTarget tryEnd_;
    JumpTarget finallyStart_;

    enum State {
        Start,
        Try,
        TryEnd,
        Catch,
        CatchEnd,
        Finally,
        FinallyEnd,
        End
    };
    State state_;

    bool hasCatch() const {
        return kind_ == TryCatch || kind_ == TryCatchFinally;
    }
    bool hasFinally() const {
        return kind_ == TryCatchFinally || kind_ == TryFinally;
    }

  public:
    TryEmitter(BytecodeEmitter* bce, Kind kind,
               ShouldUseRetVal retValKind = UseRetVal, ShouldUseControl controlKind = UseControl);

    MOZ_MUST_USE bool emitJumpOverCatchAndFinally();

    MOZ_MUST_USE bool emitTry();
    MOZ_MUST_USE bool emitCatch();

    MOZ_MUST_USE bool emitFinally(const mozilla::Maybe<uint32_t>& finallyPos = mozilla::Nothing());

    MOZ_MUST_USE bool emitEnd();

  private:
    MOZ_MUST_USE bool emitTryEnd();
    MOZ_MUST_USE bool emitCatchEnd(bool hasNext);
    MOZ_MUST_USE bool emitFinallyEnd();
};

} /* namespace frontend */
} /* namespace js */

#endif /* frontend_TryEmitter_h */