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 }