github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-context.c (about)

     1  /*
     2   * jit-context.c - Functions for manipulating JIT contexts.
     3   *
     4   * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
     5   *
     6   * This file is part of the libjit library.
     7   *
     8   * The libjit library is free software: you can redistribute it and/or
     9   * modify it under the terms of the GNU Lesser General Public License
    10   * as published by the Free Software Foundation, either version 2.1 of
    11   * the License, or (at your option) any later version.
    12   *
    13   * The libjit library is distributed in the hope that it will be useful,
    14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    16   * Lesser General Public License for more details.
    17   *
    18   * You should have received a copy of the GNU Lesser General Public
    19   * License along with the libjit library.  If not, see
    20   * <http://www.gnu.org/licenses/>.
    21   */
    22  
    23  #include "jit-internal.h"
    24  
    25  /*@
    26  
    27  Everything that is done with @code{libjit} is done relative to a context.
    28  It is possible to have more than one context at a time - each acts as an
    29  independent environment for compiling and managing code.
    30  
    31  When you want to compile a function, you create it with
    32  @code{jit_function_create}, and then populate its body with
    33  calls to the value and instruction functions.  See @xref{Values}, and
    34  @ref{Instructions} for more information on how to do this.
    35  
    36  @section Using libjit in a multi-threaded environment
    37  
    38  The library does not handle the creation, management, and destruction
    39  of threads itself.  It is up to the front-end environment to take
    40  care of that.  But the library is thread-aware, as long as you take
    41  some very simple steps.
    42  
    43  In a multi-threaded environment, you must ensure that only one
    44  thread can build functions at any one time.  Otherwise the
    45  JIT's context may become corrupted.  To protect the system,
    46  you should call @code{jit_context_build_start} before
    47  creating the function.  And then call @code{jit_context_build_end}
    48  once the function has been fully compiled.
    49  
    50  You can compile multiple functions during the one build process
    51  if you wish, which is the normal case when compiling a class.
    52  
    53  It is usually a good idea to suspend the finalization of
    54  garbage-collected objects while function building is in progress.
    55  Otherwise you may get a deadlock when the finalizer thread tries
    56  to call the builder to compile a finalization routine.  Suspension
    57  of finalization is the responsibility of the caller.
    58  
    59  @section Context functions
    60  @cindex jit-context.h
    61  
    62  The following functions are available to create, manage, and
    63  ultimately destroy JIT contexts:
    64  
    65  @*/
    66  
    67  /*@
    68   * @deftypefun jit_context_t jit_context_create (void)
    69   * Create a new context block for the JIT.  Returns NULL
    70   * if out of memory.
    71   * @end deftypefun
    72  @*/
    73  jit_context_t
    74  jit_context_create(void)
    75  {
    76  	jit_context_t context;
    77  
    78  	/* Make sure that the JIT is initialized */
    79  	jit_init();
    80  
    81  	/* Allocate memory for the context */
    82  	context = jit_cnew(struct _jit_context);
    83  	if(!context)
    84  	{
    85  		return 0;
    86  	}
    87  
    88  	/* Initialize the context and return it */
    89  	jit_mutex_create(&context->memory_lock);
    90  	jit_mutex_create(&context->builder_lock);
    91  	context->functions = 0;
    92  	context->last_function = 0;
    93  	context->on_demand_driver = _jit_function_compile_on_demand;
    94  	context->memory_manager = jit_default_memory_manager();
    95  	return context;
    96  }
    97  
    98  /*@
    99   * @deftypefun void jit_context_destroy (jit_context_t @var{context})
   100   * Destroy a JIT context block and everything that is associated with it.
   101   * It is very important that no threads within the program are currently
   102   * running compiled code when this function is called.
   103   * @end deftypefun
   104  @*/
   105  void
   106  jit_context_destroy(jit_context_t context)
   107  {
   108  	int sym;
   109  
   110  	if(!context)
   111  	{
   112  		return;
   113  	}
   114  
   115  	for(sym = 0; sym < context->num_registered_symbols; ++sym)
   116  	{
   117  		jit_free(context->registered_symbols[sym]);
   118  	}
   119  	jit_free(context->registered_symbols);
   120  
   121  	while(context->functions != 0)
   122  	{
   123  		_jit_function_destroy(context->functions);
   124  	}
   125  
   126  	_jit_memory_destroy(context);
   127  
   128  	jit_mutex_destroy(&context->memory_lock);
   129  	jit_mutex_destroy(&context->builder_lock);
   130  
   131  	jit_free(context);
   132  }
   133  
   134  /*@
   135   * @deftypefun void jit_context_build_start (jit_context_t @var{context})
   136   * This routine should be called before you start building a function
   137   * to be JIT'ed.  It acquires a lock on the context to prevent other
   138   * threads from accessing the build process, since only one thread
   139   * can be performing build operations at any one time.
   140   * @end deftypefun
   141  @*/
   142  void
   143  jit_context_build_start(jit_context_t context)
   144  {
   145  	jit_mutex_lock(&context->builder_lock);
   146  }
   147  
   148  /*@
   149   * @deftypefun void jit_context_build_end (jit_context_t @var{context})
   150   * This routine should be called once you have finished building
   151   * and compiling a function and are ready to resume normal execution.
   152   * This routine will release the build lock, allowing other threads
   153   * that are waiting on the builder to proceed.
   154   * @end deftypefun
   155  @*/
   156  void
   157  jit_context_build_end(jit_context_t context)
   158  {
   159  	jit_mutex_unlock(&context->builder_lock);
   160  }
   161  
   162  /*@
   163   * @deftypefun void jit_context_set_on_demand_driver (jit_context_t @var{context}, jit_on_demand_driver_func @var{driver})
   164   * Specify the C function to be called to drive on-demand compilation.
   165   *
   166   * When on-demand compilation is requested the default driver provided by
   167   * @code{libjit} takes the following actions:
   168   *
   169   * @enumerate
   170   * @item
   171   * The context is locked by calling @code{jit_context_build_start}.
   172   *
   173   * @item
   174   * If the function has already been compiled, @code{libjit} unlocks
   175   * the context and returns immediately.  This can happen because of race
   176   * conditions between threads: some other thread may have beaten us
   177   * to the on-demand compiler.
   178   *
   179   * @item
   180   * The user's on-demand compiler is called.  It is responsible for building
   181   * the instructions in the function's body.  It should return one of the
   182   * result codes @code{JIT_RESULT_OK}, @code{JIT_RESULT_COMPILE_ERROR},
   183   * or @code{JIT_RESULT_OUT_OF_MEMORY}.
   184   *
   185   * @item
   186   * If the user's on-demand function hasn't already done so, @code{libjit}
   187   * will call @code{jit_function_compile} to compile the function.
   188   *
   189   * @item
   190   * The context is unlocked by calling @code{jit_context_build_end} and
   191   * @code{libjit} jumps to the newly-compiled entry point.  If an error
   192   * occurs, a built-in exception of type @code{JIT_RESULT_COMPILE_ERROR}
   193   * or @code{JIT_RESULT_OUT_OF_MEMORY} will be thrown.
   194   *
   195   * @item
   196   * The entry point of the compiled function is returned from the driver.
   197   * @end enumerate
   198   *
   199   * You may need to provide your own driver if some additional actions
   200   * are required.
   201   *
   202   * @end deftypefun
   203  @*/
   204  void
   205  jit_context_set_on_demand_driver(jit_context_t context, jit_on_demand_driver_func driver)
   206  {
   207  	if (driver)
   208  	{
   209  		context->on_demand_driver = driver;
   210  	}
   211  	else
   212  	{
   213  		context->on_demand_driver = _jit_function_compile_on_demand;
   214  	}
   215  }
   216  
   217  /*@
   218   * @deftypefun void jit_context_set_memory_manager (jit_context_t @var{context}, jit_memory_manager_t @var{manager})
   219   * Specify the memory manager plug-in.
   220   * @end deftypefun
   221  @*/
   222  void
   223  jit_context_set_memory_manager(jit_context_t context, jit_memory_manager_t manager)
   224  {
   225  	/* Bail out if there is already an established memory context */
   226  	if (context->memory_context)
   227  	{
   228  		return;
   229  	}
   230  
   231  	/* Set the context memory manager */
   232  	if (manager)
   233  	{
   234  		context->memory_manager = manager;
   235  	}
   236  	else
   237  	{
   238  		context->memory_manager = jit_default_memory_manager();
   239  	}
   240  }
   241  
   242  /*@
   243   * @deftypefun int jit_context_set_meta (jit_context_t @var{context}, int @var{type}, void *@var{data}, jit_meta_free_func @var{free_data})
   244   * Tag a context with some metadata.  Returns zero if out of memory.
   245   *
   246   * Metadata may be used to store dependency graphs, branch prediction
   247   * information, or any other information that is useful to optimizers
   248   * or code generators.  It can also be used by higher level user code
   249   * to store information about the context that is specific to the
   250   * virtual machine or language.
   251   *
   252   * If the @var{type} already has some metadata associated with it, then
   253   * the previous value will be freed.
   254   * @end deftypefun
   255  @*/
   256  int
   257  jit_context_set_meta(jit_context_t context, int type, void *data, jit_meta_free_func free_data)
   258  {
   259  	return jit_meta_set(&(context->meta), type, data, free_data, 0);
   260  }
   261  
   262  /*@
   263   * @deftypefun int jit_context_set_meta_numeric (jit_context_t @var{context}, int @var{type}, jit_nuint @var{data})
   264   * Tag a context with numeric metadata.  Returns zero if out of memory.
   265   * This function is more convenient for accessing the context's
   266   * special option values:
   267   *
   268   * @table @code
   269   * @vindex JIT_OPTION_CACHE_LIMIT
   270   * @item JIT_OPTION_CACHE_LIMIT
   271   * A numeric option that indicates the maximum size in bytes of the function
   272   * cache.  If set to zero (the default), the function cache is unlimited
   273   * in size.
   274   *
   275   * @vindex JIT_OPTION_CACHE_PAGE_SIZE
   276   * @item JIT_OPTION_CACHE_PAGE_SIZE
   277   * A numeric option that indicates the size in bytes of a single page in the
   278   * function cache.  Memory is allocated for the cache in chunks of
   279   * this size.  If set to zero, the cache page size is set to an
   280   * internally-determined default (usually 128k).  The cache page size
   281   * also determines the maximum size of a single compiled function.
   282   *
   283   * @vindex JIT_OPTION_PRE_COMPILE
   284   * @item JIT_OPTION_PRE_COMPILE
   285   * A numeric option that indicates that this context is being used
   286   * for pre-compilation if it is set to a non-zero value.  Code within
   287   * pre-compiled contexts cannot be executed directly.  Instead, they
   288   * can be written out to disk in ELF format to be reloaded at
   289   * some future time.
   290   *
   291   * @vindex JIT_OPTION_DONT_FOLD
   292   * @item JIT_OPTION_DONT_FOLD
   293   * A numeric option that disables constant folding when it is set to a
   294   * non-zero value.  This is useful for debugging, as it forces @code{libjit} to
   295   * always execute constant expressions at run time, instead of at compile time.
   296   *
   297   * @vindex JIT_OPTION_POSITION_INDEPENDENT
   298   * @item JIT_OPTION_POSITION_INDEPENDENT
   299   * A numeric option that forces generation of position-independent code (PIC)
   300   * if it is set to a non-zero value. This may be mainly useful for pre-compiled
   301   * contexts.
   302   * @end table
   303   *
   304   * Metadata type values of 10000 or greater are reserved for internal use.
   305   * @end deftypefun
   306  @*/
   307  int
   308  jit_context_set_meta_numeric(jit_context_t context, int type, jit_nuint data)
   309  {
   310  	return jit_meta_set(&(context->meta), type, (void *)data, 0, 0);
   311  }
   312  
   313  /*@
   314   * @deftypefun {void *} jit_context_get_meta (jit_context_t @var{context}, int @var{type})
   315   * Get the metadata associated with a particular tag.  Returns NULL
   316   * if @var{type} does not have any metadata associated with it.
   317   * @end deftypefun
   318  @*/
   319  void *
   320  jit_context_get_meta(jit_context_t context, int type)
   321  {
   322  	return jit_meta_get(context->meta, type);
   323  }
   324  
   325  /*@
   326   * @deftypefun jit_nuint jit_context_get_meta_numeric (jit_context_t @var{context}, int @var{type})
   327   * Get the metadata associated with a particular tag.  Returns zero
   328   * if @var{type} does not have any metadata associated with it.
   329   * This version is more convenient for the pre-defined numeric option values.
   330   * @end deftypefun
   331  @*/
   332  jit_nuint
   333  jit_context_get_meta_numeric(jit_context_t context, int type)
   334  {
   335  	return (jit_nuint)jit_meta_get(context->meta, type);
   336  }
   337  
   338  /*@
   339   * @deftypefun void jit_context_free_meta (jit_context_t @var{context}, int @var{type})
   340   * Free metadata of a specific type on a context.  Does nothing if
   341   * the @var{type} does not have any metadata associated with it.
   342   * @end deftypefun
   343  @*/
   344  void
   345  jit_context_free_meta(jit_context_t context, int type)
   346  {
   347  	jit_meta_free(&(context->meta), type);
   348  }