Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/jit/jit.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * jit.c
4
 *    Provider independent JIT infrastructure.
5
 *
6
 * Code related to loading JIT providers, redirecting calls into JIT providers
7
 * and error handling.  No code specific to a specific JIT implementation
8
 * should end up here.
9
 *
10
 *
11
 * Copyright (c) 2016-2026, PostgreSQL Global Development Group
12
 *
13
 * IDENTIFICATION
14
 *    src/backend/jit/jit.c
15
 *
16
 *-------------------------------------------------------------------------
17
 */
18
#include "postgres.h"
19
20
#include <sys/types.h>
21
#include <sys/stat.h>
22
#include <unistd.h>
23
24
#include "fmgr.h"
25
#include "jit/jit.h"
26
#include "miscadmin.h"
27
#include "nodes/execnodes.h"
28
#include "portability/instr_time.h"
29
#include "storage/fd.h"
30
#include "utils/fmgrprotos.h"
31
32
/* GUCs */
33
bool    jit_enabled = false;
34
char     *jit_provider = NULL;
35
bool    jit_debugging_support = false;
36
bool    jit_dump_bitcode = false;
37
bool    jit_expressions = true;
38
bool    jit_profiling_support = false;
39
bool    jit_tuple_deforming = true;
40
double    jit_above_cost = 100000;
41
double    jit_inline_above_cost = 500000;
42
double    jit_optimize_above_cost = 500000;
43
44
static JitProviderCallbacks provider;
45
static bool provider_successfully_loaded = false;
46
static bool provider_failed_loading = false;
47
48
49
static bool provider_init(void);
50
51
52
/*
53
 * SQL level function returning whether JIT is available in the current
54
 * backend. Will attempt to load JIT provider if necessary.
55
 */
56
Datum
57
pg_jit_available(PG_FUNCTION_ARGS)
58
0
{
59
0
  PG_RETURN_BOOL(provider_init());
60
0
}
61
62
63
/*
64
 * Return whether a JIT provider has successfully been loaded, caching the
65
 * result.
66
 */
67
static bool
68
provider_init(void)
69
{
70
  char    path[MAXPGPATH];
71
  JitProviderInit init;
72
73
  /* don't even try to load if not enabled */
74
  if (!jit_enabled)
75
    return false;
76
77
  /*
78
   * Don't retry loading after failing - attempting to load JIT provider
79
   * isn't cheap.
80
   */
81
  if (provider_failed_loading)
82
    return false;
83
  if (provider_successfully_loaded)
84
    return true;
85
86
  /*
87
   * Check whether shared library exists. We do that check before actually
88
   * attempting to load the shared library (via load_external_function()),
89
   * because that'd error out in case the shlib isn't available.
90
   */
91
  snprintf(path, MAXPGPATH, "%s/%s%s", pkglib_path, jit_provider, DLSUFFIX);
92
  elog(DEBUG1, "probing availability of JIT provider at %s", path);
93
  if (!pg_file_exists(path))
94
  {
95
    elog(DEBUG1,
96
       "provider not available, disabling JIT for current session");
97
    provider_failed_loading = true;
98
    return false;
99
  }
100
101
  /*
102
   * If loading functions fails, signal failure. We do so because
103
   * load_external_function() might error out despite the above check if
104
   * e.g. the library's dependencies aren't installed. We want to signal
105
   * ERROR in that case, so the user is notified, but we don't want to
106
   * continually retry.
107
   */
108
  provider_failed_loading = true;
109
110
  /* and initialize */
111
  init = (JitProviderInit)
112
    load_external_function(path, "_PG_jit_provider_init", true, NULL);
113
  init(&provider);
114
115
  provider_successfully_loaded = true;
116
  provider_failed_loading = false;
117
118
  elog(DEBUG1, "successfully loaded JIT provider in current session");
119
120
  return true;
121
}
122
123
/*
124
 * Reset JIT provider's error handling. This'll be called after an error has
125
 * been thrown and the main-loop has re-established control.
126
 */
127
void
128
jit_reset_after_error(void)
129
5.21k
{
130
5.21k
  if (provider_successfully_loaded)
131
0
    provider.reset_after_error();
132
5.21k
}
133
134
/*
135
 * Release resources required by one JIT context.
136
 */
137
void
138
jit_release_context(JitContext *context)
139
0
{
140
0
  if (provider_successfully_loaded)
141
0
    provider.release_context(context);
142
143
0
  pfree(context);
144
0
}
145
146
/*
147
 * Ask provider to JIT compile an expression.
148
 *
149
 * Returns true if successful, false if not.
150
 */
151
bool
152
jit_compile_expr(struct ExprState *state)
153
0
{
154
  /*
155
   * We can easily create a one-off context for functions without an
156
   * associated PlanState (and thus EState). But because there's no executor
157
   * shutdown callback that could deallocate the created function, they'd
158
   * live to the end of the transactions, where they'd be cleaned up by the
159
   * resowner machinery. That can lead to a noticeable amount of memory
160
   * usage, and worse, trigger some quadratic behaviour in gdb. Therefore,
161
   * at least for now, don't create a JITed function in those circumstances.
162
   */
163
0
  if (!state->parent)
164
0
    return false;
165
166
  /* if no jitting should be performed at all */
167
0
  if (!(state->parent->state->es_jit_flags & PGJIT_PERFORM))
168
0
    return false;
169
170
  /* or if expressions aren't JITed */
171
0
  if (!(state->parent->state->es_jit_flags & PGJIT_EXPR))
172
0
    return false;
173
174
  /* this also takes !jit_enabled into account */
175
0
  if (provider_init())
176
0
    return provider.compile_expr(state);
177
178
0
  return false;
179
0
}
180
181
/* Aggregate JIT instrumentation information */
182
void
183
InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
184
0
{
185
0
  dst->created_functions += add->created_functions;
186
0
  INSTR_TIME_ADD(dst->generation_counter, add->generation_counter);
187
0
  INSTR_TIME_ADD(dst->deform_counter, add->deform_counter);
188
0
  INSTR_TIME_ADD(dst->inlining_counter, add->inlining_counter);
189
0
  INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
190
0
  INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
191
0
}