summaryrefslogtreecommitdiffstats
path: root/js/src/jit/Ion.h
blob: 018eea5cb56f2249d1e1cb32f0db86f86fa16a0f (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * 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 jit_Ion_h
#define jit_Ion_h

#include "mozilla/MemoryReporting.h"

#include "jscntxt.h"
#include "jscompartment.h"

#include "jit/CompileWrappers.h"
#include "jit/JitOptions.h"

namespace js {
namespace jit {

class TempAllocator;

enum MethodStatus
{
    Method_Error,
    Method_CantCompile,
    Method_Skipped,
    Method_Compiled
};

enum AbortReason {
    AbortReason_Alloc,
    AbortReason_Inlining,
    AbortReason_PreliminaryObjects,
    AbortReason_Disable,
    AbortReason_Error,
    AbortReason_NoAbort
};

// A JIT context is needed to enter into either an JIT method or an instance
// of a JIT compiler. It points to a temporary allocator and the active
// JSContext, either of which may be nullptr, and the active compartment, which
// will not be nullptr.

class JitContext
{
  public:
    JitContext(JSContext* cx, TempAllocator* temp);
    JitContext(ExclusiveContext* cx, TempAllocator* temp);
    JitContext(CompileRuntime* rt, CompileCompartment* comp, TempAllocator* temp);
    JitContext(CompileRuntime* rt, TempAllocator* temp);
    explicit JitContext(CompileRuntime* rt);
    explicit JitContext(TempAllocator* temp);
    JitContext();
    ~JitContext();

    // Running context when executing on the main thread. Not available during
    // compilation.
    JSContext* cx;

    // Allocator for temporary memory during compilation.
    TempAllocator* temp;

    // Wrappers with information about the current runtime/compartment for use
    // during compilation.
    CompileRuntime* runtime;
    CompileCompartment* compartment;

    bool onMainThread() const {
        return runtime && runtime->onMainThread();
    }
    bool hasProfilingScripts() const {
        return runtime && !!runtime->profilingScripts();
    }

    int getNextAssemblerId() {
        return assemblerCount_++;
    }
  private:
    JitContext* prev_;
    int assemblerCount_;
};

// Initialize Ion statically for all JSRuntimes.
MOZ_MUST_USE bool InitializeIon();

// Get and set the current JIT context.
JitContext* GetJitContext();
JitContext* MaybeGetJitContext();

void SetJitContext(JitContext* ctx);

bool CanIonCompileScript(JSContext* cx, JSScript* script, bool osr);

MOZ_MUST_USE bool IonCompileScriptForBaseline(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);

MethodStatus CanEnter(JSContext* cx, RunState& state);
MethodStatus CanEnterUsingFastInvoke(JSContext* cx, HandleScript script, uint32_t numActualArgs);

MethodStatus
Recompile(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode* osrPc,
          bool force);

enum JitExecStatus
{
    // The method call had to be aborted due to a stack limit check. This
    // error indicates that Ion never attempted to clean up frames.
    JitExec_Aborted,

    // The method call resulted in an error, and IonMonkey has cleaned up
    // frames.
    JitExec_Error,

    // The method call succeeded and returned a value.
    JitExec_Ok
};

static inline bool
IsErrorStatus(JitExecStatus status)
{
    return status == JitExec_Error || status == JitExec_Aborted;
}

struct EnterJitData;

MOZ_MUST_USE bool SetEnterJitData(JSContext* cx, EnterJitData& data, RunState& state,
                                  MutableHandle<GCVector<Value>> vals);

JitExecStatus IonCannon(JSContext* cx, RunState& state);

// Used to enter Ion from C++ natives like Array.map. Called from FastInvokeGuard.
JitExecStatus FastInvoke(JSContext* cx, HandleFunction fun, CallArgs& args);

// Walk the stack and invalidate active Ion frames for the invalid scripts.
void Invalidate(TypeZone& types, FreeOp* fop,
                const RecompileInfoVector& invalid, bool resetUses = true,
                bool cancelOffThread = true);
void Invalidate(JSContext* cx, const RecompileInfoVector& invalid, bool resetUses = true,
                bool cancelOffThread = true);
void Invalidate(JSContext* cx, JSScript* script, bool resetUses = true,
                bool cancelOffThread = true);

void ToggleBarriers(JS::Zone* zone, bool needs);

class IonBuilder;
class MIRGenerator;
class LIRGraph;
class CodeGenerator;

MOZ_MUST_USE bool OptimizeMIR(MIRGenerator* mir);
LIRGraph* GenerateLIR(MIRGenerator* mir);
CodeGenerator* GenerateCode(MIRGenerator* mir, LIRGraph* lir);
CodeGenerator* CompileBackEnd(MIRGenerator* mir);

void AttachFinishedCompilations(JSContext* cx);
void FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder,
                            const AutoLockHelperThreadState& lock);

void LinkIonScript(JSContext* cx, HandleScript calleescript);
uint8_t* LazyLinkTopActivation(JSContext* cx);

static inline bool
IsIonEnabled(JSContext* cx)
{
    // The ARM64 Ion engine is not yet implemented.
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
    return false;
#else
    return cx->options().ion() &&
           cx->options().baseline() &&
           cx->runtime()->jitSupportsFloatingPoint;
#endif
}

inline bool
IsIonInlinablePC(jsbytecode* pc) {
    // CALL, FUNCALL, FUNAPPLY, EVAL, NEW (Normal Callsites)
    // GETPROP, CALLPROP, and LENGTH. (Inlined Getters)
    // SETPROP, SETNAME, SETGNAME (Inlined Setters)
    return IsCallPC(pc) || IsGetPropPC(pc) || IsSetPropPC(pc);
}

inline bool
TooManyActualArguments(unsigned nargs)
{
    return nargs > JitOptions.maxStackArgs;
}

inline bool
TooManyFormalArguments(unsigned nargs)
{
    return nargs >= SNAPSHOT_MAX_NARGS || TooManyActualArguments(nargs);
}

inline size_t
NumLocalsAndArgs(JSScript* script)
{
    size_t num = 1 /* this */ + script->nfixed();
    if (JSFunction* fun = script->functionNonDelazifying())
        num += fun->nargs();
    return num;
}

bool OffThreadCompilationAvailable(JSContext* cx);

void ForbidCompilation(JSContext* cx, JSScript* script);

void PurgeCaches(JSScript* script);
size_t SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf);
void DestroyJitScripts(FreeOp* fop, JSScript* script);
void TraceJitScripts(JSTracer* trc, JSScript* script);

bool JitSupportsFloatingPoint();
bool JitSupportsUnalignedAccesses();
bool JitSupportsSimd();
bool JitSupportsAtomics();

} // namespace jit
} // namespace js

#endif /* jit_Ion_h */