Jit/pyjit.h (99 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#pragma once
#include "Python.h"
#include "frameobject.h"
#include "genobject.h"
#include "Jit/pyjit_result.h"
#include "Jit/pyjit_typeslots.h"
#ifdef __cplusplus
#include "Jit/hir/preload.h"
#endif
// Offset of the state field in jit::GenFooterData for fast access from C code.
// This value is verified by static_assert in runtime.h.
#define _PY_GEN_JIT_DATA_STATE_OFFSET 24
#ifndef Py_LIMITED_API
#ifdef __cplusplus
extern "C" {
#endif
enum InitStateJitConfig { JIT_NOT_INITIALIZED, JIT_INITIALIZED, JIT_FINALIZED };
enum FrameModeJitConfig { PY_FRAME = 0, SHADOW_FRAME };
/* Accessors for internal jit config */
PyAPI_FUNC(int) _PyJIT_IsJitConfigAllow_jit_list_wildcards(void);
PyAPI_FUNC(int) _PyJIT_IsJitConfigCompile_all_static_functions(void);
PyAPI_FUNC(size_t) _PyJIT_GetJitConfigBatch_compile_workers(void);
PyAPI_FUNC(int) _PyJIT_IsJitConfigMultithreaded_compile_test(void);
/*
* Offset of the code object within a jit::CodeRuntime
*/
PyAPI_DATA(int64_t) __strobe_CodeRuntime_py_code;
/*
* This defines the global public API for the JIT that is consumed by the
* runtime.
*
* These methods assume that the GIL is held unless it is explicitly stated
* otherwise.
*/
/*
* Initialize any global state required by the JIT.
*
* This must be called before attempting to use the JIT.
*
* Returns 0 on success or -1 on error.
*/
PyAPI_FUNC(int) _PyJIT_Initialize(void);
/*
* Enable the global JIT.
*
* _PyJIT_Initialize must be called before calling this.
*
* Returns 1 if the JIT is enabled and 0 otherwise.
*/
PyAPI_FUNC(int) _PyJIT_Enable(void);
/*
* Disable the global JIT.
*/
PyAPI_FUNC(void) _PyJIT_Disable(void);
/*
* Returns 1 if JIT compilation is enabled and 0 otherwise.
*/
PyAPI_FUNC(int) _PyJIT_IsEnabled(void);
/*
* After-fork callback for child processes. Performs any cleanup necessary for
* per-process state, including handling of Linux perf pid maps.
*/
PyAPI_FUNC(void) _PyJIT_AfterFork_Child(void);
/*
* Enable type slot specialization.
*/
PyAPI_FUNC(int) _PyJIT_EnableTypeSlots(void);
/*
* Returns 1 if type slot specialization is enabled and 0 otherwise.
*/
PyAPI_FUNC(int) _PyJIT_AreTypeSlotsEnabled(void);
/*
Enable the HIR inliner.
*/
PyAPI_FUNC(void) _PyJIT_EnableHIRInliner(void);
/*
Disable the HIR inliner.
*/
PyAPI_FUNC(void) _PyJIT_DisableHIRInliner(void);
/*
* Returns 1 if the HIR inliner is enabled and 0 otherwise.
*/
PyAPI_FUNC(int) _PyJIT_IsHIRInlinerEnabled(void);
/*
* JITs slot functions for the type object, and handles setting up
* deoptimization support for the type. The caller provides the type object and
* a struct containing the pointers to the current slot functions.
*
* Returns PYJIT_RESULT_OK if all operations succeed, or one of the error codes
* on failure.
*/
PyAPI_FUNC(_PyJIT_Result)
_PyJIT_SpecializeType(PyTypeObject* type, _PyJIT_TypeSlots* slots);
/*
* JIT compile func and patch its entry point.
*
* On success, positional only calls to func will use the JIT compiled version.
*
* Returns PYJIT_RESULT_OK on success.
*/
PyAPI_FUNC(_PyJIT_Result) _PyJIT_CompileFunction(PyFunctionObject* func);
/*
* Registers a function with the JIT to be compiled in the future.
*
* The JIT will still be informed by _PyJIT_CompileFunction before the
* function executes for the first time. The JIT can choose to compile
* the function at some future point. Currently the JIT will compile
* the function before it shuts down to make sure all eligable functions
* were compiled.
*
* The JIT will not keep the function alive, instead it will be informed
* that the function is being de-allocated via _PyJIT_UnregisterFunction
* before the function goes away.
*
* Returns 1 if the function is registered with JIT or is already compiled,
* and 0 otherwise.
*/
PyAPI_FUNC(int) _PyJIT_RegisterFunction(PyFunctionObject* func);
/*
* Informs the JIT that a type, function, or code object is being created,
* modified, or destroyed.
*/
PyAPI_FUNC(void) _PyJIT_TypeCreated(PyTypeObject* type);
PyAPI_FUNC(void) _PyJIT_TypeModified(PyTypeObject* type);
PyAPI_FUNC(void) _PyJIT_TypeNameModified(PyTypeObject* type);
PyAPI_FUNC(void) _PyJIT_TypeDestroyed(PyTypeObject* type);
PyAPI_FUNC(void) _PyJIT_FuncModified(PyFunctionObject* func);
PyAPI_FUNC(void) _PyJIT_FuncDestroyed(PyFunctionObject* func);
PyAPI_FUNC(void) _PyJIT_CodeDestroyed(PyCodeObject* code);
/*
* Clean up any resources allocated by the JIT.
*
* This is intended to be called at interpreter shutdown in Py_Finalize.
*
* Returns 0 on success or -1 on error.
*/
PyAPI_FUNC(int) _PyJIT_Finalize(void);
/*
* Returns whether the function specified in `func` is on the jit-list.
*
* Returns 0 if the given function is not on the jit-list, and non-zero
* otherwise.
*
* Always returns 1 if the JIT list is not specified.
*/
PyAPI_FUNC(int) _PyJIT_OnJitList(PyFunctionObject* func);
/*
* Returns a boolean indicating whether or not jitted functions should use a
* shadow frame object by default instead of a full PyFrameObject.
*/
PyAPI_FUNC(int) _PyJIT_ShadowFrame(void);
/* Dict-watching callbacks, invoked by dictobject.c when appropriate. */
/*
* Called when the value at a key is modified (value will contain the new
* value) or deleted (value will be NULL).
*/
PyAPI_FUNC(void)
_PyJIT_NotifyDictKey(PyObject* dict, PyObject* key, PyObject* value);
/*
* Called when a dict is cleared, rather than sending individual notifications
* for every key. The dict is still in a watched state, and further callbacks
* for it will be invoked as appropriate.
*/
PyAPI_FUNC(void) _PyJIT_NotifyDictClear(PyObject* dict);
/*
* Called when a dict has changed in a way that is incompatible with watching,
* or is about to be freed. No more callbacks will be invoked for this dict.
*/
PyAPI_FUNC(void) _PyJIT_NotifyDictUnwatch(PyObject* dict);
/*
* Gets the global cache for the given globals dictionary and key. The global
* that is pointed to will automatically be updated as builtins and globals
* change. The value that is pointed to will be NULL if the dictionaries can
* no longer be tracked or if the value is no longer defined, in which case
* the dictionaries need to be consulted. This will return NULL if the required
* tracking cannot be initialized.
*/
PyAPI_FUNC(PyObject**) _PyJIT_GetGlobalCache(PyObject* globals, PyObject* key);
/*
* Gets the cache for the given dictionary and key. The value that is pointed
* to will automatically be updated as the dictionary changes. The value that
* is pointed to will be NULL if the dictionaries can no longer be tracked or if
* the value is no longer defined, in which case the dictionaries need to be
* consulted. This will return NULL if the required tracking cannot be
* initialized.
*/
PyAPI_FUNC(PyObject**) _PyJIT_GetDictCache(PyObject* dict, PyObject* key);
/*
* Clears internal caches associated with the JIT. This may cause a degradation
* of performance and is only intended for use for detecting memory leaks.
*/
PyAPI_FUNC(void) _PyJIT_ClearDictCaches(void);
/*
* Send into/resume a suspended JIT generator and return the result.
*/
PyAPI_FUNC(PyObject*) _PyJIT_GenSend(
PyGenObject* gen,
PyObject* arg,
int exc,
PyFrameObject* f,
PyThreadState* tstate,
int finish_yield_from);
/*
* Materialize the frame for gen. Returns a new reference.
*/
PyAPI_FUNC(PyFrameObject*) _PyJIT_GenMaterializeFrame(PyGenObject* gen);
/*
* Visit owned references in a JIT-backed generator object.
*/
PyAPI_FUNC(int)
_PyJIT_GenVisitRefs(PyGenObject* gen, visitproc visit, void* arg);
/*
* Release any JIT-related data in a PyGenObject.
*/
PyAPI_FUNC(void) _PyJIT_GenDealloc(PyGenObject* gen);
/*
* Extract overall JIT state for generator. Implemented as a macro for perf
* in C code that doesn't have access to C++ types.
*/
#define _PyJIT_GenState(gen) \
((_PyJitGenState)((char*)gen->gi_jit_data)[_PY_GEN_JIT_DATA_STATE_OFFSET])
#define _PYJIT_MarkGenCompleted(gen) \
(*((_PyJitGenState*)((char*)gen->gi_jit_data + _PY_GEN_JIT_DATA_STATE_OFFSET)) = \
_PyJitGenState_Completed)
/*
* Return current sub-iterator from JIT generator or NULL if there is none.
*/
PyAPI_FUNC(PyObject*) _PyJIT_GenYieldFromValue(PyGenObject* gen);
/*
* Specifies the offset from a JITed function entry point where the re-entry
* point for calling with the correct bound args lives */
#define JITRT_CALL_REENTRY_OFFSET (-9)
/*
* Fixes the JITed function entry point up to be the re-entry point after
* binding the args */
#define JITRT_GET_REENTRY(entry) \
((vectorcallfunc)(((char*)entry) + JITRT_CALL_REENTRY_OFFSET))
/*
* Specifies the offset from a JITed function entry point where the static
* entry point lives */
#define JITRT_STATIC_ENTRY_OFFSET (-14)
/*
* Fixes the JITed function entry point up to be the static entry point after
* binding the args */
#define JITRT_GET_STATIC_ENTRY(entry) \
((vectorcallfunc)(((char*)entry) + JITRT_STATIC_ENTRY_OFFSET))
/*
* Checks if the given function is JITed.
* Returns 1 if the function is JITed, 0 if not.
*/
PyAPI_FUNC(int) _PyJIT_IsCompiled(PyObject* func);
/*
* Returns a borrowed reference to the globals for the top-most Python function
* associated with tstate.
*/
PyAPI_FUNC(PyObject*) _PyJIT_GetGlobals(PyThreadState* tstate);
/*
* Indicates whether or not newly-created interpreter threads should have type
* profiling enabled by default.
*/
extern int g_profile_new_interp_threads;
/*
* Record a type profile for the current instruction.
*/
PyAPI_FUNC(void) _PyJIT_ProfileCurrentInstr(
PyFrameObject* frame,
PyObject** stack_top,
int opcode,
int oparg);
/*
* Record profiled instructions for the given code object upon exit from a
* frame, some of which may not have had their types recorded.
*/
PyAPI_FUNC(void)
_PyJIT_CountProfiledInstrs(PyCodeObject* code, Py_ssize_t count);
/*
* Get and clear, or just clear, information about the recorded type profiles.
*/
PyAPI_FUNC(PyObject*) _PyJIT_GetAndClearTypeProfiles(void);
PyAPI_FUNC(void) _PyJIT_ClearTypeProfiles(void);
/*
* Notify the JIT that type has been modified.
*/
PyAPI_FUNC(void) _PyJIT_TypeModified(PyTypeObject* type);
#ifdef __cplusplus
bool _PyJIT_UseHugePages();
} /* extern "C" */
#endif
#ifdef __cplusplus
namespace jit {
bool isPreloaded(BorrowedRef<PyFunctionObject> func);
const hir::Preloader& getPreloader(BorrowedRef<PyFunctionObject> func);
} // namespace jit
#endif
#endif /* Py_LIMITED_API */