blob: bd4edecb27c975e1ba3e05fee5c71f20e1f0dd1d [file] [log] [blame]
/* -*- 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_MIRGenerator_h
#define jit_MIRGenerator_h
// This file declares the data structures used to build a control-flow graph
// containing MIR.
#include "mozilla/Atomics.h"
#include <stdarg.h>
#include "jscntxt.h"
#include "jscompartment.h"
#include "jit/CompileInfo.h"
#include "jit/JitAllocPolicy.h"
#include "jit/JitCompartment.h"
#include "jit/MIR.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
#include "jit/RegisterSets.h"
namespace js {
namespace jit {
class MIRGraph;
class OptimizationInfo;
class MIRGenerator
{
public:
MIRGenerator(CompileCompartment* compartment, const JitCompileOptions& options,
TempAllocator* alloc, MIRGraph* graph,
const CompileInfo* info, const OptimizationInfo* optimizationInfo,
bool usesSignalHandlersForAsmJSOOB = false);
TempAllocator& alloc() {
return *alloc_;
}
MIRGraph& graph() {
return *graph_;
}
bool ensureBallast() {
return alloc().ensureBallast();
}
const JitRuntime* jitRuntime() const {
return GetJitContext()->runtime->jitRuntime();
}
const CompileInfo& info() const {
return *info_;
}
const OptimizationInfo& optimizationInfo() const {
return *optimizationInfo_;
}
template <typename T>
T* allocate(size_t count = 1) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(count, &bytes)))
return nullptr;
return static_cast<T*>(alloc().allocate(bytes));
}
// Set an error state and prints a message. Returns false so errors can be
// propagated up.
bool abort(const char* message, ...);
bool abortFmt(const char* message, va_list ap);
bool errored() const {
return error_;
}
bool instrumentedProfiling() {
if (!instrumentedProfilingIsCached_) {
instrumentedProfiling_ = GetJitContext()->runtime->spsProfiler().enabled();
instrumentedProfilingIsCached_ = true;
}
return instrumentedProfiling_;
}
bool isProfilerInstrumentationEnabled() {
return !compilingAsmJS() && instrumentedProfiling();
}
bool isOptimizationTrackingEnabled() {
return isProfilerInstrumentationEnabled() && !info().isAnalysis();
}
bool safeForMinorGC() const {
return safeForMinorGC_;
}
void setNotSafeForMinorGC() {
safeForMinorGC_ = false;
}
// Whether the main thread is trying to cancel this build.
bool shouldCancel(const char* why) {
maybePause();
return cancelBuild_;
}
void cancel() {
cancelBuild_ = true;
}
void maybePause() {
if (pauseBuild_ && *pauseBuild_)
PauseCurrentHelperThread();
}
void setPauseFlag(mozilla::Atomic<bool, mozilla::Relaxed>* pauseBuild) {
pauseBuild_ = pauseBuild;
}
void disable() {
abortReason_ = AbortReason_Disable;
}
AbortReason abortReason() {
return abortReason_;
}
bool compilingAsmJS() const {
return info_->compilingAsmJS();
}
uint32_t maxAsmJSStackArgBytes() const {
MOZ_ASSERT(compilingAsmJS());
return maxAsmJSStackArgBytes_;
}
uint32_t resetAsmJSMaxStackArgBytes() {
MOZ_ASSERT(compilingAsmJS());
uint32_t old = maxAsmJSStackArgBytes_;
maxAsmJSStackArgBytes_ = 0;
return old;
}
void setAsmJSMaxStackArgBytes(uint32_t n) {
MOZ_ASSERT(compilingAsmJS());
maxAsmJSStackArgBytes_ = n;
}
void setPerformsCall() {
performsCall_ = true;
}
bool performsCall() const {
return performsCall_;
}
// Traverses the graph to find if there's any SIMD instruction. Costful but
// the value is cached, so don't worry about calling it several times.
bool usesSimd();
bool modifiesFrameArguments() const {
return modifiesFrameArguments_;
}
typedef Vector<ObjectGroup*, 0, JitAllocPolicy> ObjectGroupVector;
// When abortReason() == AbortReason_PreliminaryObjects, all groups with
// preliminary objects which haven't been analyzed yet.
const ObjectGroupVector& abortedPreliminaryGroups() const {
return abortedPreliminaryGroups_;
}
public:
CompileCompartment* compartment;
protected:
const CompileInfo* info_;
const OptimizationInfo* optimizationInfo_;
TempAllocator* alloc_;
JSFunction* fun_;
uint32_t nslots_;
MIRGraph* graph_;
AbortReason abortReason_;
bool shouldForceAbort_; // Force AbortReason_Disable
ObjectGroupVector abortedPreliminaryGroups_;
bool error_;
mozilla::Atomic<bool, mozilla::Relaxed>* pauseBuild_;
mozilla::Atomic<bool, mozilla::Relaxed> cancelBuild_;
uint32_t maxAsmJSStackArgBytes_;
bool performsCall_;
bool usesSimd_;
bool usesSimdCached_;
// Keep track of whether frame arguments are modified during execution.
// RegAlloc needs to know this as spilling values back to their register
// slots is not compatible with that.
bool modifiesFrameArguments_;
bool instrumentedProfiling_;
bool instrumentedProfilingIsCached_;
bool safeForMinorGC_;
void addAbortedPreliminaryGroup(ObjectGroup* group);
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
bool usesSignalHandlersForAsmJSOOB_;
#endif
void setForceAbort() {
shouldForceAbort_ = true;
}
bool shouldForceAbort() {
return shouldForceAbort_;
}
#if defined(JS_ION_PERF)
AsmJSPerfSpewer asmJSPerfSpewer_;
public:
AsmJSPerfSpewer& perfSpewer() { return asmJSPerfSpewer_; }
#endif
public:
const JitCompileOptions options;
bool needsAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* access) const;
size_t foldableOffsetRange(const MAsmJSHeapAccess* access) const;
private:
GraphSpewer gs_;
public:
GraphSpewer& graphSpewer() {
return gs_;
}
};
} // namespace jit
} // namespace js
#endif /* jit_MIRGenerator_h */