summaryrefslogtreecommitdiff
path: root/js/src/wasm/WasmFrameIterator.h
blob: a62a2d3ee59ccf3029c2907ae33aae871abaf0ff (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 *
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef wasm_frame_iterator_h
#define wasm_frame_iterator_h

#include "js/ProfilingFrameIterator.h"

class JSAtom;

namespace js {

class WasmActivation;
namespace jit { class MacroAssembler; }

namespace wasm {

class CallSite;
class Code;
class CodeRange;
class SigIdDesc;
struct CallThunk;
struct FuncOffsets;
struct ProfilingOffsets;
struct TrapOffset;

// Iterates over the frames of a single WasmActivation, called synchronously
// from C++ in the thread of the asm.js.
//
// The one exception is that this iterator may be called from the interrupt
// callback which may be called asynchronously from asm.js code; in this case,
// the backtrace may not be correct. That being said, we try our best printing
// an informative message to the user and at least the name of the innermost
// function stack frame.
class FrameIterator
{
    const WasmActivation* activation_;
    const Code* code_;
    const CallSite* callsite_;
    const CodeRange* codeRange_;
    uint8_t* fp_;
    uint8_t* pc_;
    bool missingFrameMessage_;

    void settle();

  public:
    explicit FrameIterator();
    explicit FrameIterator(const WasmActivation& activation);
    void operator++();
    bool done() const;
    const char* filename() const;
    const char16_t* displayURL() const;
    bool mutedErrors() const;
    JSAtom* functionDisplayAtom() const;
    unsigned lineOrBytecode() const;
    inline void* fp() const { return fp_; }
    inline uint8_t* pc() const { return pc_; }
};

// An ExitReason describes the possible reasons for leaving compiled wasm code
// or the state of not having left compiled wasm code (ExitReason::None).
enum class ExitReason : uint32_t
{
    None,          // default state, the pc is in wasm code
    ImportJit,     // fast-path call directly into JIT code
    ImportInterp,  // slow-path call into C++ Invoke()
    Native,        // call to native C++ code (e.g., Math.sin, ToInt32(), interrupt)
    Trap           // call to trap handler for the trap in WasmActivation::trap
};

// Iterates over the frames of a single WasmActivation, given an
// asynchrously-interrupted thread's state. If the activation's
// module is not in profiling mode, the activation is skipped.
class ProfilingFrameIterator
{
    const WasmActivation* activation_;
    const Code* code_;
    const CodeRange* codeRange_;
    uint8_t* callerFP_;
    void* callerPC_;
    void* stackAddress_;
    ExitReason exitReason_;

    void initFromFP();

  public:
    ProfilingFrameIterator();
    explicit ProfilingFrameIterator(const WasmActivation& activation);
    ProfilingFrameIterator(const WasmActivation& activation,
                           const JS::ProfilingFrameIterator::RegisterState& state);
    void operator++();
    bool done() const { return !codeRange_; }

    void* stackAddress() const { MOZ_ASSERT(!done()); return stackAddress_; }
    const char* label() const;
};

// Prologue/epilogue code generation

void
GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                     ProfilingOffsets* offsets);
void
GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                     ProfilingOffsets* offsets);
void
GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
                         FuncOffsets* offsets);
void
GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);

// Runtime patching to enable/disable profiling

void
ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled);

void
ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled);

void
ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled);

} // namespace wasm
} // namespace js

#endif // wasm_frame_iterator_h