Basic JIT provider and error handling infrastructure.
authorAndres Freund <andres@anarazel.de>
Thu, 22 Mar 2018 02:28:28 +0000 (19:28 -0700)
committerAndres Freund <andres@anarazel.de>
Thu, 22 Mar 2018 02:28:28 +0000 (19:28 -0700)
This commit introduces:

1) JIT provider abstraction, which allows JIT functionality to be
   implemented in separate shared libraries. That's desirable because
   it allows to install JIT support as a separate package, and because
   it allows experimentation with different forms of JITing.
2) JITContexts which can be, using functions introduced in follow up
   commits, used to emit JITed functions, and have them be cleaned up
   on error.
3) The outline of a LLVM JIT provider, which will be fleshed out in
   subsequent commits.

Documentation for GUCs added, and for JIT in general, will be added in
later commits.

Author: Andres Freund, with architectural input from Jeff Davis
Discussion: https://postgr.es/m/20170901064131.tazjxwus3k2w3ybh@alap3.anarazel.de

18 files changed:
src/Makefile
src/backend/Makefile
src/backend/jit/Makefile [new file with mode: 0644]
src/backend/jit/jit.c [new file with mode: 0644]
src/backend/jit/llvm/Makefile [new file with mode: 0644]
src/backend/jit/llvm/llvmjit.c [new file with mode: 0644]
src/backend/jit/llvm/llvmjit_error.cpp [new file with mode: 0644]
src/backend/tcop/postgres.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/backend/utils/resowner/resowner.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/jit/jit.h [new file with mode: 0644]
src/include/jit/llvmjit.h [new file with mode: 0644]
src/include/utils/resowner_private.h
src/tools/pgindent/exclude_file_patterns
src/tools/pgindent/typedefs.list

index febbcede7d0e50c79c37b9bb20c2be260dad1d1f..bcdbd9588aa437ce3a41123e71be07154653645b 100644 (file)
@@ -31,6 +31,10 @@ SUBDIRS = \
    test/isolation \
    test/perl
 
+ifeq ($(with_llvm), yes)
+SUBDIRS += backend/jit/llvm
+endif
+
 # There are too many interdependencies between the subdirectories, so
 # don't attempt parallel make here.
 .NOTPARALLEL:
index 4a28267339a2520b0adc3595632e99594c59844d..6450c5a9597afb8fb89518cad1d881b9a7b0e8be 100644 (file)
@@ -19,7 +19,8 @@ include $(top_builddir)/src/Makefile.global
 
 SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
    main nodes optimizer port postmaster regex replication rewrite \
-   statistics storage tcop tsearch utils $(top_builddir)/src/timezone
+   statistics storage tcop tsearch utils $(top_builddir)/src/timezone \
+   jit
 
 include $(srcdir)/common.mk
 
diff --git a/src/backend/jit/Makefile b/src/backend/jit/Makefile
new file mode 100644 (file)
index 0000000..cdb9009
--- /dev/null
@@ -0,0 +1,22 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+#    Makefile for JIT code that's provider independent.
+#
+# Note that the LLVM JIT provider is recursed into by src/Makefile,
+# not from here.
+#
+# IDENTIFICATION
+#    src/backend/jit/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/jit
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+override CPPFLAGS += -DDLSUFFIX=\"$(DLSUFFIX)\"
+
+OBJS = jit.o
+
+include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
new file mode 100644 (file)
index 0000000..6c842a0
--- /dev/null
@@ -0,0 +1,156 @@
+/*-------------------------------------------------------------------------
+ *
+ * jit.c
+ *   Provider independent JIT infrastructure.
+ *
+ * Code related to loading JIT providers, redirecting calls into JIT providers
+ * and error handling.  No code specific to a specific JIT implementation
+ * should end up here.
+ *
+ *
+ * Copyright (c) 2016-2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/backend/jit/jit.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+
+#include "fmgr.h"
+#include "jit/jit.h"
+#include "miscadmin.h"
+#include "utils/resowner_private.h"
+#include "utils/fmgrprotos.h"
+
+
+/* GUCs */
+bool       jit_enabled = true;
+char      *jit_provider = "llvmjit";
+
+static JitProviderCallbacks provider;
+static bool provider_successfully_loaded = false;
+static bool provider_failed_loading = false;
+
+
+static bool provider_init(void);
+static bool file_exists(const char *name);
+
+
+/*
+ * SQL level function returning whether JIT is available in the current
+ * backend. Will attempt to load JIT provider if necessary.
+ */
+Datum
+pg_jit_available(PG_FUNCTION_ARGS)
+{
+   PG_RETURN_BOOL(provider_init());
+}
+
+
+/*
+ * Return whether a JIT provider has successfully been loaded, caching the
+ * result.
+ */
+static bool
+provider_init(void)
+{
+   char        path[MAXPGPATH];
+   JitProviderInit init;
+
+   /* don't even try to load if not enabled */
+   if (!jit_enabled)
+       return false;
+
+   /*
+    * Don't retry loading after failing - attempting to load JIT provider
+    * isn't cheap.
+    */
+   if (provider_failed_loading)
+       return false;
+   if (provider_successfully_loaded)
+       return true;
+
+   /*
+    * Check whether shared library exists. We do that check before actually
+    * attempting to load the shared library (via load_external_function()),
+    * because that'd error out in case the shlib isn't available.
+    */
+   snprintf(path, MAXPGPATH, "%s/%s%s", pkglib_path, jit_provider, DLSUFFIX);
+   elog(DEBUG1, "probing availability of JIT provider at %s", path);
+   if (!file_exists(path))
+   {
+       elog(DEBUG1,
+            "provider not available, disabling JIT for current session");
+       provider_failed_loading = true;
+       return false;
+   }
+
+   /*
+    * If loading functions fails, signal failure. We do so because
+    * load_external_function() might error out despite the above check if
+    * e.g. the library's dependencies aren't installed. We want to signal
+    * ERROR in that case, so the user is notified, but we don't want to
+    * continually retry.
+    */
+   provider_failed_loading = true;
+
+   /* and initialize */
+   init = (JitProviderInit)
+       load_external_function(path, "_PG_jit_provider_init", true, NULL);
+   init(&provider);
+
+   provider_successfully_loaded = true;
+   provider_failed_loading = false;
+
+   elog(DEBUG1, "successfully loaded JIT provider in current session");
+
+   return true;
+}
+
+/*
+ * Reset JIT provider's error handling. This'll be called after an error has
+ * been thrown and the main-loop has re-established control.
+ */
+void
+jit_reset_after_error(void)
+{
+   if (provider_successfully_loaded)
+       provider.reset_after_error();
+}
+
+/*
+ * Release resources required by one JIT context.
+ */
+void
+jit_release_context(JitContext *context)
+{
+   if (provider_successfully_loaded)
+       provider.release_context(context);
+
+   ResourceOwnerForgetJIT(context->resowner, PointerGetDatum(context));
+   pfree(context);
+}
+
+static bool
+file_exists(const char *name)
+{
+   struct stat st;
+
+   AssertArg(name != NULL);
+
+   if (stat(name, &st) == 0)
+       return S_ISDIR(st.st_mode) ? false : true;
+   else if (!(errno == ENOENT || errno == ENOTDIR))
+       ereport(ERROR,
+               (errcode_for_file_access(),
+                errmsg("could not access file \"%s\": %m", name)));
+
+   return false;
+}
diff --git a/src/backend/jit/llvm/Makefile b/src/backend/jit/llvm/Makefile
new file mode 100644 (file)
index 0000000..856b94e
--- /dev/null
@@ -0,0 +1,55 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+#    Makefile the LLVM JIT provider, building it into a shared library.
+#
+# Note that this file is recursed into from src/Makefile, not by the
+# parent directory..
+#
+# IDENTIFICATION
+#    src/backend/jit/llvm/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/jit/llvm
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+ifneq ($(with_llvm), yes)
+    $(error "not building with LLVM support")
+endif
+
+PGFILEDESC = "llvmjit - JIT using LLVM"
+NAME = llvmjit
+
+# All files in this directy use LLVM.
+CFLAGS += $(LLVM_CFLAGS)
+CXXFLAGS += $(LLVM_CXXFLAGS)
+override CPPFLAGS := $(LLVM_CPPFLAGS) $(CPPFLAGS)
+SHLIB_LINK += $(LLVM_LIBS)
+SHLIB_PREREQS += submake-generated-headers
+
+# Because this module includes C++ files, we need to use a C++
+# compiler for linking. Makefile.shlib uses $(COMPILER) to build
+# loadable modules.
+override COMPILER = $(CXX) $(CFLAGS)
+
+OBJS=$(WIN32RES)
+
+# Infrastructure
+OBJS += llvmjit.o llvmjit_error.o
+# Code generation
+OBJS +=
+
+all: all-shared-lib
+
+install: all installdirs install-lib
+
+installdirs: installdirs-lib
+
+uninstall: uninstall-lib
+
+include $(top_srcdir)/src/Makefile.shlib
+
+clean distclean maintainer-clean: clean-lib
+   rm -f $(OBJS)
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
new file mode 100644 (file)
index 0000000..9c57922
--- /dev/null
@@ -0,0 +1,113 @@
+/*-------------------------------------------------------------------------
+ *
+ * llvmjit.c
+ *   Core part of the LLVM JIT provider.
+ *
+ * Copyright (c) 2016-2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/backend/jit/llvm/llvmjit.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "jit/llvmjit.h"
+
+#include "miscadmin.h"
+
+#include "utils/memutils.h"
+#include "utils/resowner_private.h"
+#include "storage/ipc.h"
+
+
+#include <llvm-c/Target.h>
+
+
+static bool llvm_session_initialized = false;
+
+
+static void llvm_release_context(JitContext *context);
+static void llvm_session_initialize(void);
+static void llvm_shutdown(int code, Datum arg);
+
+
+PG_MODULE_MAGIC;
+
+
+/*
+ * Initialize LLVM JIT provider.
+ */
+void
+_PG_jit_provider_init(JitProviderCallbacks *cb)
+{
+   cb->reset_after_error = llvm_reset_after_error;
+   cb->release_context = llvm_release_context;
+}
+
+/*
+ * Create a context for JITing work.
+ *
+ * The context, including subsidiary resources, will be cleaned up either when
+ * the context is explicitly released, or when the lifetime of
+ * CurrentResourceOwner ends (usually the end of the current [sub]xact).
+ */
+LLVMJitContext *
+llvm_create_context(int jitFlags)
+{
+   LLVMJitContext *context;
+
+   llvm_assert_in_fatal_section();
+
+   llvm_session_initialize();
+
+   ResourceOwnerEnlargeJIT(CurrentResourceOwner);
+
+   context = MemoryContextAllocZero(TopMemoryContext,
+                                    sizeof(LLVMJitContext));
+   context->base.flags = jitFlags;
+
+   /* ensure cleanup */
+   context->base.resowner = CurrentResourceOwner;
+   ResourceOwnerRememberJIT(CurrentResourceOwner, PointerGetDatum(context));
+
+   return context;
+}
+
+/*
+ * Release resources required by one llvm context.
+ */
+static void
+llvm_release_context(JitContext *context)
+{
+}
+
+/*
+ * Per session initialization.
+ */
+static void
+llvm_session_initialize(void)
+{
+   MemoryContext oldcontext;
+
+   if (llvm_session_initialized)
+       return;
+
+   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+
+   LLVMInitializeNativeTarget();
+   LLVMInitializeNativeAsmPrinter();
+   LLVMInitializeNativeAsmParser();
+
+   before_shmem_exit(llvm_shutdown, 0);
+
+   llvm_session_initialized = true;
+
+   MemoryContextSwitchTo(oldcontext);
+}
+
+static void
+llvm_shutdown(int code, Datum arg)
+{
+}
diff --git a/src/backend/jit/llvm/llvmjit_error.cpp b/src/backend/jit/llvm/llvmjit_error.cpp
new file mode 100644 (file)
index 0000000..edc1c47
--- /dev/null
@@ -0,0 +1,141 @@
+/*-------------------------------------------------------------------------
+ *
+ * llvmjit_error.cpp
+ *   LLVM error related handling that requires interfacing with C++
+ *
+ * Unfortunately neither (re)setting the C++ new handler, nor the LLVM OOM
+ * handler are exposed to C. Therefore this file wraps the necesary code.
+ *
+ * Copyright (c) 2016-2018, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/backend/jit/llvm/llvmjit_error.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+extern "C"
+{
+#include "postgres.h"
+}
+
+#include <llvm/Support/ErrorHandling.h>
+
+#include "jit/llvmjit.h"
+
+
+static int fatal_new_handler_depth = 0;
+static std::new_handler old_new_handler = NULL;
+
+static void fatal_system_new_handler(void);
+#if LLVM_VERSION_MAJOR > 4
+static void fatal_llvm_new_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
+#endif
+static void fatal_llvm_error_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
+
+
+/*
+ * Enter a section in which C++ and LLVM errors are treated as FATAL errors.
+ *
+ * This is necessary for LLVM as LLVM's error handling for such cases
+ * (exit()ing, throwing std::bad_alloc() if compiled with exceptions, abort())
+ * isn't compatible with postgres error handling.  Thus in section where LLVM
+ * code, not LLVM generated functions!, is executing, standard new, LLVM OOM
+ * and LLVM fatal errors (some OOM errors masquerade as those) are redirected
+ * to our own error handlers.
+ *
+ * These error handlers FATAL, because there's no reliable way from within
+ * LLVM to throw an error that's guaranteed not to corrupt LLVM's state.
+ *
+ * To avoid disturbing extensions using C++ and/or LLVM, these handlers are
+ * unset when not executing LLVM code. There is no need to call
+ * llvm_leave_fatal_on_oom() when ERRORing out, error recovery resets the
+ * handlers in that case.
+ */
+void
+llvm_enter_fatal_on_oom(void)
+{
+   if (fatal_new_handler_depth == 0)
+   {
+       old_new_handler = std::set_new_handler(fatal_system_new_handler);
+#if LLVM_VERSION_MAJOR > 4
+       llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
+#endif
+       llvm::install_fatal_error_handler(fatal_llvm_error_handler);
+   }
+   fatal_new_handler_depth++;
+}
+
+/*
+ * Leave fatal error section started with llvm_enter_fatal_on_oom().
+ */
+void
+llvm_leave_fatal_on_oom(void)
+{
+   fatal_new_handler_depth--;
+   if (fatal_new_handler_depth == 0)
+   {
+       std::set_new_handler(old_new_handler);
+#if LLVM_VERSION_MAJOR > 4
+       llvm::remove_bad_alloc_error_handler();
+#endif
+       llvm::remove_fatal_error_handler();
+   }
+}
+
+/*
+ * Reset fatal error handling. This should only be called in error recovery
+ * loops like PostgresMain()'s.
+ */
+void
+llvm_reset_after_error(void)
+{
+   if (fatal_new_handler_depth != 0)
+   {
+       std::set_new_handler(old_new_handler);
+#if LLVM_VERSION_MAJOR > 4
+       llvm::remove_bad_alloc_error_handler();
+#endif
+       llvm::remove_fatal_error_handler();
+   }
+   fatal_new_handler_depth = 0;
+}
+
+void
+llvm_assert_in_fatal_section(void)
+{
+   Assert(fatal_new_handler_depth > 0);
+}
+
+static void
+fatal_system_new_handler(void)
+{
+   ereport(FATAL,
+           (errcode(ERRCODE_OUT_OF_MEMORY),
+            errmsg("out of memory"),
+            errdetail("while in LLVM")));
+}
+
+#if LLVM_VERSION_MAJOR > 4
+static void
+fatal_llvm_new_handler(void *user_data,
+                      const std::string& reason,
+                      bool gen_crash_diag)
+{
+   ereport(FATAL,
+           (errcode(ERRCODE_OUT_OF_MEMORY),
+            errmsg("out of memory"),
+            errdetail("While in LLVM: %s", reason.c_str())));
+}
+#endif
+
+static void
+fatal_llvm_error_handler(void *user_data,
+                        const std::string& reason,
+                        bool gen_crash_diag)
+{
+   ereport(FATAL,
+           (errcode(ERRCODE_OUT_OF_MEMORY),
+            errmsg("fatal llvm error: %s",
+                   reason.c_str())));
+}
index 6dc2095b9a765f4f682eb43652ff0c0ca2f0599e..f7aa4a74844a70472b686d0785d0bf37f7405520 100644 (file)
@@ -42,6 +42,7 @@
 #include "catalog/pg_type.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
+#include "jit/jit.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
 #include "libpq/pqsignal.h"
@@ -3950,6 +3951,8 @@ PostgresMain(int argc, char *argv[],
        /* We also want to cleanup temporary slots on error. */
        ReplicationSlotCleanup();
 
+       jit_reset_after_error();
+
        /*
         * Now return to normal top-level context and clear ErrorContext for
         * next time.
index 153373ead029d5ae4d1b7ef49ffb8f1a5ac109ef..afb1007842a01512564f574e7568b83a6982fcb1 100644 (file)
@@ -42,6 +42,7 @@
 #include "commands/variable.h"
 #include "commands/trigger.h"
 #include "funcapi.h"
+#include "jit/jit.h"
 #include "libpq/auth.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -1714,6 +1715,16 @@ static struct config_bool ConfigureNamesBool[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"jit", PGC_USERSET, QUERY_TUNING_OTHER,
+           gettext_noop("Allow JIT compilation."),
+           NULL
+       },
+       &jit_enabled,
+       true,
+       NULL, NULL, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
@@ -3707,6 +3718,17 @@ static struct config_string ConfigureNamesString[] =
        check_wal_consistency_checking, assign_wal_consistency_checking, NULL
    },
 
+   {
+       {"jit_provider", PGC_POSTMASTER, FILE_LOCATIONS,
+           gettext_noop("JIT provider to use."),
+           NULL,
+           GUC_SUPERUSER_ONLY
+       },
+       &jit_provider,
+       "llvmjit",
+       NULL, NULL, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL
index 048bf4cccd7447aacf8073dbbbdf5ca756dca35f..91eacacdc9794a73a05d17a4b0c09cf62e14a37e 100644 (file)
 
 #dynamic_library_path = '$libdir'
 
+#jit = on              # allow JIT compilation
+#jit_provider = 'llvmjit'      # JIT implementation to use
 
 #------------------------------------------------------------------------------
 # LOCK MANAGEMENT
index e09a4f1ddb48d3aed9a7cadaf2c85fec685e73f4..bce021e1001dff306570232af10e1f03e5302b23 100644 (file)
@@ -21,6 +21,7 @@
 #include "postgres.h"
 
 #include "access/hash.h"
+#include "jit/jit.h"
 #include "storage/predicate.h"
 #include "storage/proc.h"
 #include "utils/memutils.h"
@@ -124,6 +125,7 @@ typedef struct ResourceOwnerData
    ResourceArray snapshotarr;  /* snapshot references */
    ResourceArray filearr;      /* open temporary files */
    ResourceArray dsmarr;       /* dynamic shmem segments */
+   ResourceArray jitarr;       /* JIT contexts */
 
    /* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
    int         nlocks;         /* number of owned locks */
@@ -437,6 +439,7 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name)
    ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL));
    ResourceArrayInit(&(owner->filearr), FileGetDatum(-1));
    ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
+   ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL));
 
    return owner;
 }
@@ -538,6 +541,14 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
                PrintDSMLeakWarning(res);
            dsm_detach(res);
        }
+
+       /* Ditto for JIT contexts */
+       while (ResourceArrayGetAny(&(owner->jitarr), &foundres))
+       {
+           JitContext *context = (JitContext *) PointerGetDatum(foundres);
+
+           jit_release_context(context);
+       }
    }
    else if (phase == RESOURCE_RELEASE_LOCKS)
    {
@@ -685,6 +696,7 @@ ResourceOwnerDelete(ResourceOwner owner)
    Assert(owner->snapshotarr.nitems == 0);
    Assert(owner->filearr.nitems == 0);
    Assert(owner->dsmarr.nitems == 0);
+   Assert(owner->jitarr.nitems == 0);
    Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
 
    /*
@@ -711,6 +723,7 @@ ResourceOwnerDelete(ResourceOwner owner)
    ResourceArrayFree(&(owner->snapshotarr));
    ResourceArrayFree(&(owner->filearr));
    ResourceArrayFree(&(owner->dsmarr));
+   ResourceArrayFree(&(owner->jitarr));
 
    pfree(owner);
 }
@@ -1253,3 +1266,38 @@ PrintDSMLeakWarning(dsm_segment *seg)
    elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
         dsm_segment_handle(seg));
 }
+
+/*
+ * Make sure there is room for at least one more entry in a ResourceOwner's
+ * JIT context reference array.
+ *
+ * This is separate from actually inserting an entry because if we run out of
+ * memory, it's critical to do so *before* acquiring the resource.
+ */
+void
+ResourceOwnerEnlargeJIT(ResourceOwner owner)
+{
+   ResourceArrayEnlarge(&(owner->jitarr));
+}
+
+/*
+ * Remember that a JIT context is owned by a ResourceOwner
+ *
+ * Caller must have previously done ResourceOwnerEnlargeJIT()
+ */
+void
+ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle)
+{
+   ResourceArrayAdd(&(owner->jitarr), handle);
+}
+
+/*
+ * Forget that a JIT context is owned by a ResourceOwner
+ */
+void
+ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
+{
+   if (!ResourceArrayRemove(&(owner->jitarr), handle))
+       elog(ERROR, "JIT context %p is not owned by resource owner %s",
+            DatumGetPointer(handle), owner->name);
+}
index 4c290abb4d65ae005aecfc8ca7f96bd1ec28b349..0ddf6a77c1a56993f21a41ea5af88b3b843121fe 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201803212
+#define CATALOG_VERSION_NO 201803213
 
 #endif
index 871000b94b516e8c639dbb16b2489a9bf9a460fa..bfc90098f8671a1bac7eb4866ee54d578974f668 100644 (file)
@@ -3371,6 +3371,8 @@ DATA(insert OID = 3935 ( pg_sleep_for         PGNSP PGUID 14 1 0 0 0 f f f t f v s 1 0
 DESCR("sleep for the specified interval");
 DATA(insert OID = 3936 ( pg_sleep_until            PGNSP PGUID 14 1 0 0 0 f f f t f v s 1 0 2278 "1184" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.pg_sleep(extract(epoch from $1) operator(pg_catalog.-) extract(epoch from pg_catalog.clock_timestamp()))" _null_ _null_ _null_ ));
 DESCR("sleep until the specified time");
+DATA(insert OID = 315 (  pg_jit_available  PGNSP PGUID 12 1 0 0 0 f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_jit_available _null_ _null_ _null_ ));
+DESCR("Is JIT compilation available in this session?");
 
 DATA(insert OID = 2971 (  text             PGNSP PGUID 12 1 0 0 0 f f f t f i s 1 0 25 "16" _null_ _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ ));
 DESCR("convert boolean to text");
diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h
new file mode 100644 (file)
index 0000000..a2f3dd9
--- /dev/null
@@ -0,0 +1,46 @@
+/*-------------------------------------------------------------------------
+ * jit.h
+ *   Provider independent JIT infrastructure.
+ *
+ * Copyright (c) 2016-2018, PostgreSQL Global Development Group
+ *
+ * src/include/jit/jit.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef JIT_H
+#define JIT_H
+
+#include "utils/resowner.h"
+
+
+typedef struct JitContext
+{
+   int         flags;
+
+   ResourceOwner resowner;
+} JitContext;
+
+typedef struct JitProviderCallbacks JitProviderCallbacks;
+
+extern void _PG_jit_provider_init(JitProviderCallbacks *cb);
+typedef void (*JitProviderInit) (JitProviderCallbacks *cb);
+typedef void (*JitProviderResetAfterErrorCB) (void);
+typedef void (*JitProviderReleaseContextCB) (JitContext *context);
+
+struct JitProviderCallbacks
+{
+   JitProviderResetAfterErrorCB reset_after_error;
+   JitProviderReleaseContextCB release_context;
+};
+
+
+/* GUCs */
+extern bool jit_enabled;
+extern char *jit_provider;
+
+
+extern void jit_reset_after_error(void);
+extern void jit_release_context(JitContext *context);
+
+#endif                         /* JIT_H */
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
new file mode 100644 (file)
index 0000000..187ebe2
--- /dev/null
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+ * llvmjit.h
+ *   LLVM JIT provider.
+ *
+ * Copyright (c) 2016-2018, PostgreSQL Global Development Group
+ *
+ * src/include/jit/llvmjit.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef LLVMJIT_H
+#define LLVMJIT_H
+
+#ifndef USE_LLVM
+#error "llvmjit.h should only be included by code dealing with llvm"
+#endif
+
+#include <llvm-c/Types.h>
+
+
+/*
+ * File needs to be includable by both C and C++ code, and include other
+ * headers doing the same. Therefore wrap C portion in our own extern "C" if
+ * in C++ mode.
+ */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#include "jit/jit.h"
+
+
+typedef struct LLVMJitContext
+{
+   JitContext  base;
+} LLVMJitContext;
+
+extern void llvm_enter_fatal_on_oom(void);
+extern void llvm_leave_fatal_on_oom(void);
+extern void llvm_reset_after_error(void);
+extern void llvm_assert_in_fatal_section(void);
+
+extern LLVMJitContext *llvm_create_context(int jitFlags);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif                         /* LLVMJIT_H */
index 22b377c0df5b0f426e8253a97f7f3ebb2f47af64..44dc99eb2672abb223c6fd86f78aa979cdcc6bf4 100644 (file)
@@ -88,4 +88,11 @@ extern void ResourceOwnerRememberDSM(ResourceOwner owner,
 extern void ResourceOwnerForgetDSM(ResourceOwner owner,
                       dsm_segment *);
 
+/* support for JITContext management */
+extern void ResourceOwnerEnlargeJIT(ResourceOwner owner);
+extern void ResourceOwnerRememberJIT(ResourceOwner owner,
+                                    Datum handle);
+extern void ResourceOwnerForgetJIT(ResourceOwner owner,
+                                  Datum handle);
+
 #endif                         /* RESOWNER_PRIVATE_H */
index cb2f902a90f2178f7d0df488bbfcd14764573dbe..65c42c131d01eb8a6892fbf57b120bc94e72955b 100644 (file)
@@ -5,3 +5,4 @@
 /ecpg/test/expected/
 /snowball/libstemmer/
 /pl/plperl/ppport\.h$
+/jit/llvmjit\.h$
index d4765ce3b011f5834b2014e5218d48154fd810ef..543cb17e410028d7e5c9c8a5d48fd2c721cca58f 100644 (file)
@@ -1055,6 +1055,8 @@ IterateForeignScan_function
 IterateJsonStringValuesState
 JEntry
 JHashState
+JitContext
+JitProviderCallbacks
 JOBOBJECTINFOCLASS
 JOBOBJECT_BASIC_LIMIT_INFORMATION
 JOBOBJECT_BASIC_UI_RESTRICTIONS
@@ -1099,6 +1101,7 @@ LDAPMessage
 LDAPURLDesc
 LDAP_TIMEVAL
 LINE
+LLVMJitContext
 LOCALLOCK
 LOCALLOCKOWNER
 LOCALLOCKTAG