/* -*- 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 */