LCOV - code coverage report
Current view: top level - src - runtime_ccall.cpp (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 152 193 78.8 %
Date: 2022-07-16 23:42:53 Functions: 10 13 76.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 73 124 58.9 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : #include "llvm-version.h"
       4                 :            : #include <map>
       5                 :            : #include <string>
       6                 :            : #include <llvm/ADT/StringMap.h>
       7                 :            : #include <llvm/Support/Host.h>
       8                 :            : #include <llvm/Support/raw_ostream.h>
       9                 :            : 
      10                 :            : #include "julia.h"
      11                 :            : #include "julia_internal.h"
      12                 :            : #include "processor.h"
      13                 :            : #include "julia_assert.h"
      14                 :            : 
      15                 :            : #ifndef _OS_WINDOWS_
      16                 :            : #include <sys/mman.h>
      17                 :            : #if defined(_OS_DARWIN_) && !defined(MAP_ANONYMOUS)
      18                 :            : #define MAP_ANONYMOUS MAP_ANON
      19                 :            : #endif
      20                 :            : #endif
      21                 :            : 
      22                 :            : using namespace llvm;
      23                 :            : 
      24                 :            : // --- library symbol lookup ---
      25                 :            : 
      26                 :            : // map from user-specified lib names to handles
      27                 :            : static std::map<std::string, void*> libMap;
      28                 :            : static jl_mutex_t libmap_lock;
      29                 :            : extern "C"
      30                 :     293253 : void *jl_get_library_(const char *f_lib, int throw_err)
      31                 :            : {
      32         [ +  + ]:     293253 :     if (f_lib == NULL)
      33                 :     236553 :         return jl_RTLD_DEFAULT_handle;
      34                 :            : #ifdef _OS_WINDOWS_
      35                 :            :     if (f_lib == JL_EXE_LIBNAME)
      36                 :            :         return jl_exe_handle;
      37                 :            :     if (f_lib == JL_LIBJULIA_INTERNAL_DL_LIBNAME)
      38                 :            :         return jl_libjulia_internal_handle;
      39                 :            :     if (f_lib == JL_LIBJULIA_DL_LIBNAME)
      40                 :            :         return jl_libjulia_handle;
      41                 :            : #endif
      42                 :      56700 :     JL_LOCK(&libmap_lock);
      43                 :            :     // This is the only operation we do on the map, which doesn't invalidate
      44                 :            :     // any references or iterators.
      45                 :      56700 :     void **map_slot = &libMap[f_lib];
      46                 :      56700 :     void *hnd = *map_slot;
      47         [ +  + ]:      56700 :     if (hnd == NULL) {
      48                 :      22925 :         hnd = jl_load_dynamic_library(f_lib, JL_RTLD_DEFAULT, throw_err);
      49         [ +  + ]:       2924 :         if (hnd != NULL)
      50                 :       2923 :             *map_slot = hnd;
      51                 :            :     }
      52                 :      36699 :     JL_UNLOCK(&libmap_lock);
      53                 :      36699 :     return hnd;
      54                 :            : }
      55                 :            : 
      56                 :            : extern "C" JL_DLLEXPORT
      57                 :     108242 : void *jl_load_and_lookup(const char *f_lib, const char *f_name, _Atomic(void*) *hnd)
      58                 :            : {
      59                 :     108242 :     void *handle = jl_atomic_load_acquire(hnd);
      60         [ +  + ]:     108242 :     if (!handle)
      61                 :      22871 :         jl_atomic_store_release(hnd, (handle = jl_get_library(f_lib)));
      62                 :            :     void * ptr;
      63                 :      88241 :     jl_dlsym(handle, f_name, &ptr, 1);
      64                 :      88241 :     return ptr;
      65                 :            : }
      66                 :            : 
      67                 :            : // jl_load_and_lookup, but with library computed at run time on first call
      68                 :            : extern "C" JL_DLLEXPORT
      69                 :          0 : void *jl_lazy_load_and_lookup(jl_value_t *lib_val, const char *f_name)
      70                 :            : {
      71                 :            :     char *f_lib;
      72                 :            : 
      73         [ #  # ]:          0 :     if (jl_is_symbol(lib_val))
      74                 :          0 :         f_lib = jl_symbol_name((jl_sym_t*)lib_val);
      75         [ #  # ]:          0 :     else if (jl_is_string(lib_val))
      76                 :          0 :         f_lib = jl_string_data(lib_val);
      77                 :            :     else
      78                 :          0 :         jl_type_error("ccall", (jl_value_t*)jl_symbol_type, lib_val);
      79                 :            :     void *ptr;
      80                 :          0 :     jl_dlsym(jl_get_library(f_lib), f_name, &ptr, 1);
      81                 :          0 :     return ptr;
      82                 :            : }
      83                 :            : 
      84                 :            : // miscellany
      85                 :          0 : std::string jl_get_cpu_name_llvm(void)
      86                 :            : {
      87                 :          0 :     return llvm::sys::getHostCPUName().str();
      88                 :            : }
      89                 :            : 
      90                 :          0 : std::string jl_get_cpu_features_llvm(void)
      91                 :            : {
      92                 :          0 :     StringMap<bool> HostFeatures;
      93                 :          0 :     llvm::sys::getHostCPUFeatures(HostFeatures);
      94                 :          0 :     std::string attr;
      95         [ #  # ]:          0 :     for (auto &ele: HostFeatures) {
      96         [ #  # ]:          0 :         if (ele.getValue()) {
      97         [ #  # ]:          0 :             if (!attr.empty()) {
      98                 :          0 :                 attr.append(",+");
      99                 :            :             }
     100                 :            :             else {
     101                 :          0 :                 attr.append("+");
     102                 :            :             }
     103                 :          0 :             attr.append(ele.getKey().str());
     104                 :            :         }
     105                 :            :     }
     106                 :            :     // Explicitly disabled features need to be added at the end so that
     107                 :            :     // they are not re-enabled by other features that implies them by default.
     108         [ #  # ]:          0 :     for (auto &ele: HostFeatures) {
     109         [ #  # ]:          0 :         if (!ele.getValue()) {
     110         [ #  # ]:          0 :             if (!attr.empty()) {
     111                 :          0 :                 attr.append(",-");
     112                 :            :             }
     113                 :            :             else {
     114                 :          0 :                 attr.append("-");
     115                 :            :             }
     116                 :          0 :             attr.append(ele.getKey().str());
     117                 :            :         }
     118                 :            :     }
     119                 :          0 :     return attr;
     120                 :            : }
     121                 :            : 
     122                 :            : extern "C" JL_DLLEXPORT
     123                 :        563 : jl_value_t *jl_get_JIT(void)
     124                 :            : {
     125                 :       1126 :     const std::string& HostJITName = "ORCJIT";
     126                 :        563 :     return jl_pchar_to_string(HostJITName.data(), HostJITName.size());
     127                 :            : }
     128                 :            : 
     129                 :            : #ifndef MAXHOSTNAMELEN
     130                 :            : # define MAXHOSTNAMELEN 256
     131                 :            : #endif
     132                 :            : 
     133                 :            : // Form a file name from a pattern made by replacing tokens,
     134                 :            : // similar to many of those provided by ssh_config TOKENS:
     135                 :            : //
     136                 :            : //           %%    A literal `%'.
     137                 :            : //           %p    The process PID
     138                 :            : //           %d    Local user's home directory.
     139                 :            : //           %i    The local user ID.
     140                 :            : //           %L    The local hostname.
     141                 :            : //           %l    The local hostname, including the domain name.
     142                 :            : //           %u    The local username.
     143                 :          9 : std::string jl_format_filename(StringRef output_pattern)
     144                 :            : {
     145                 :         18 :     std::string buf;
     146                 :         18 :     raw_string_ostream outfile(buf);
     147                 :          9 :     bool special = false;
     148                 :            :     char hostname[MAXHOSTNAMELEN + 1];
     149                 :            :     uv_passwd_t pwd;
     150                 :          9 :     bool got_pwd = false;
     151         [ +  + ]:        225 :     for (auto c : output_pattern) {
     152         [ +  + ]:        216 :         if (special) {
     153   [ +  +  +  -  :          8 :             if (!got_pwd && (c == 'i' || c == 'd' || c == 'u')) {
             +  +  -  + ]
     154                 :          1 :                 int r = uv_os_get_passwd(&pwd);
     155         [ +  - ]:          1 :                 if (r == 0)
     156                 :          1 :                     got_pwd = true;
     157                 :            :             }
     158   [ +  +  +  +  :          8 :             switch (c) {
                   +  + ]
     159                 :          1 :             case 'p':
     160                 :          1 :                 outfile << uv_os_getpid();
     161                 :          1 :                 break;
     162                 :          1 :             case 'd':
     163         [ +  - ]:          1 :                 if (got_pwd)
     164                 :          1 :                     outfile << pwd.homedir;
     165                 :          1 :                 break;
     166                 :          1 :             case 'i':
     167         [ +  - ]:          1 :                 if (got_pwd)
     168                 :          1 :                     outfile << pwd.uid;
     169                 :          1 :                 break;
     170                 :          2 :             case 'l':
     171                 :            :             case 'L':
     172         [ +  - ]:          2 :                 if (gethostname(hostname, sizeof(hostname)) == 0) {
     173                 :          2 :                     hostname[sizeof(hostname) - 1] = '\0'; /* Null terminate, just to be safe. */
     174                 :          2 :                     outfile << hostname;
     175                 :            :                 }
     176                 :            : #ifndef _OS_WINDOWS_
     177   [ +  +  +  -  :          2 :                 if (c == 'l' && getdomainname(hostname, sizeof(hostname)) == 0) {
                   +  + ]
     178                 :          1 :                     hostname[sizeof(hostname) - 1] = '\0'; /* Null terminate, just to be safe. */
     179                 :          1 :                     outfile << hostname;
     180                 :            :                 }
     181                 :            : #endif
     182                 :          2 :                 break;
     183                 :          1 :             case 'u':
     184         [ +  - ]:          1 :                 if (got_pwd)
     185                 :          1 :                     outfile << pwd.username;
     186                 :          1 :                 break;
     187                 :          2 :             default:
     188                 :          2 :                 outfile << c;
     189                 :          2 :                 break;
     190                 :            :             }
     191                 :          8 :             special = false;
     192                 :            :         }
     193         [ +  + ]:        208 :         else if (c == '%') {
     194                 :          8 :             special = true;
     195                 :            :         }
     196                 :            :         else {
     197                 :        200 :             outfile << c;
     198                 :            :         }
     199                 :            :     }
     200         [ +  + ]:          9 :     if (got_pwd)
     201                 :          1 :         uv_os_free_passwd(&pwd);
     202                 :          9 :     return outfile.str();
     203                 :            : }
     204                 :            : 
     205                 :          9 : extern "C" JL_DLLEXPORT char *jl_format_filename(const char *output_pattern)
     206                 :            : {
     207                 :          9 :     return strdup(jl_format_filename(StringRef(output_pattern)).c_str());
     208                 :            : }
     209                 :            : 
     210                 :            : 
     211                 :            : static uv_mutex_t trampoline_lock; // for accesses to the cache and freelist
     212                 :            : 
     213                 :            : static void *trampoline_freelist;
     214                 :            : 
     215                 :       2195 : static void *trampoline_alloc() JL_NOTSAFEPOINT // lock taken by caller
     216                 :            : {
     217                 :       2195 :     const int sz = 64; // oversized for most platforms. todo: use precise value?
     218         [ +  + ]:       2195 :     if (!trampoline_freelist) {
     219                 :         33 :         int last_errno = errno;
     220                 :            : #ifdef _OS_WINDOWS_
     221                 :            :         DWORD last_error = GetLastError();
     222                 :            :         void *mem = VirtualAlloc(NULL, jl_page_size,
     223                 :            :                 MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
     224                 :            :         if (mem == NULL)
     225                 :            :             jl_throw(jl_memory_exception);
     226                 :            :         SetLastError(last_error);
     227                 :            : #else
     228                 :         33 :         void *mem = mmap(0, jl_page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
     229                 :            :                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     230                 :         33 :         errno = last_errno;
     231         [ -  + ]:         33 :         if (mem == MAP_FAILED)
     232                 :          0 :             jl_throw(jl_memory_exception);
     233                 :            : #endif
     234                 :         33 :         errno = last_errno;
     235                 :         33 :         void *next = NULL;
     236         [ -  + ]:         33 :         assert(sz < jl_page_size);
     237         [ +  + ]:       2145 :         for (size_t i = 0; i + sz <= jl_page_size; i += sz) {
     238                 :       2112 :             void **curr = (void**)((char*)mem + i);
     239                 :       2112 :             *curr = next;
     240                 :       2112 :             next = (void*)curr;
     241                 :            :         }
     242                 :         33 :         trampoline_freelist = next;
     243                 :            :     }
     244                 :       2195 :     void *tramp = trampoline_freelist;
     245                 :       2195 :     trampoline_freelist = *(void**)tramp;
     246                 :       2195 :     return tramp;
     247                 :            : }
     248                 :            : 
     249                 :       2181 : static void trampoline_free(void *tramp) JL_NOTSAFEPOINT    // lock taken by caller
     250                 :            : {
     251                 :       2181 :     *(void**)tramp = trampoline_freelist;
     252                 :       2181 :     trampoline_freelist = tramp;
     253                 :       2181 : }
     254                 :            : 
     255                 :       2181 : static void trampoline_deleter(void **f) JL_NOTSAFEPOINT
     256                 :            : {
     257                 :       2181 :     void *tramp = f[0];
     258                 :       2181 :     void *fobj = f[1];
     259                 :       2181 :     void *cache = f[2];
     260                 :       2181 :     void *nval = f[3];
     261                 :       2181 :     f[0] = NULL;
     262                 :       2181 :     f[2] = NULL;
     263                 :       2181 :     f[3] = NULL;
     264                 :       2181 :     uv_mutex_lock(&trampoline_lock);
     265         [ +  - ]:       2181 :     if (tramp)
     266                 :       2181 :         trampoline_free(tramp);
     267   [ +  -  +  - ]:       2181 :     if (fobj && cache)
     268                 :       2181 :         ptrhash_remove((htable_t*)cache, fobj);
     269         [ +  - ]:       2181 :     if (nval)
     270                 :       2181 :         free(nval);
     271                 :       2181 :     uv_mutex_unlock(&trampoline_lock);
     272                 :       2181 : }
     273                 :            : 
     274                 :            : typedef void *(*init_trampoline_t)(void *tramp, void **nval) JL_NOTSAFEPOINT;
     275                 :            : 
     276                 :            : // Use of `cache` is not clobbered in JL_TRY
     277                 :            : JL_GCC_IGNORE_START("-Wclobbered")
     278                 :            : extern "C" JL_DLLEXPORT
     279                 :      22257 : jl_value_t *jl_get_cfunction_trampoline(
     280                 :            :     // dynamic inputs:
     281                 :            :     jl_value_t *fobj,
     282                 :            :     jl_datatype_t *result_type,
     283                 :            :     // call-site constants:
     284                 :            :     htable_t *cache, // weakref htable indexed by (fobj, vals)
     285                 :            :     jl_svec_t *fill,
     286                 :            :     init_trampoline_t init_trampoline,
     287                 :            :     jl_unionall_t *env,
     288                 :            :     jl_value_t **vals)
     289                 :            : {
     290                 :            :     // lookup (fobj, vals) in cache
     291                 :      22257 :     uv_mutex_lock(&trampoline_lock);
     292         [ +  + ]:      22285 :     if (!cache->table)
     293                 :         19 :         htable_new(cache, 1);
     294         [ -  + ]:      22285 :     if (fill != jl_emptysvec) {
     295                 :          0 :         htable_t **cache2 = (htable_t**)ptrhash_bp(cache, (void*)vals);
     296                 :          0 :         cache = *cache2;
     297         [ #  # ]:          0 :         if (cache == HT_NOTFOUND) {
     298                 :          0 :             cache = htable_new((htable_t*)malloc_s(sizeof(htable_t)), 1);
     299                 :          0 :             *cache2 = cache;
     300                 :            :         }
     301                 :            :     }
     302                 :      22285 :     void *tramp = ptrhash_get(cache, (void*)fobj);
     303                 :      22285 :     uv_mutex_unlock(&trampoline_lock);
     304         [ +  + ]:      22259 :     if (tramp != HT_NOTFOUND) {
     305         [ -  + ]:      20062 :         assert((jl_datatype_t*)jl_typeof(tramp) == result_type);
     306                 :      20062 :         return (jl_value_t*)tramp;
     307                 :            :     }
     308                 :            : 
     309                 :            :     // not found, allocate a new one
     310                 :       2197 :     size_t n = jl_svec_len(fill);
     311                 :       2197 :     void **nval = (void**)malloc_s(sizeof(void*) * (n + 1));
     312                 :       2193 :     nval[0] = (void*)fobj;
     313                 :            :     jl_value_t *result;
     314   [ +  -  +  + ]:       4377 :     JL_TRY {
     315         [ -  + ]:       2190 :         for (size_t i = 0; i < n; i++) {
     316                 :          0 :             jl_value_t *sparam_val = jl_instantiate_type_in_env(jl_svecref(fill, i), env, vals);
     317         [ #  # ]:          0 :             if (sparam_val != (jl_value_t*)jl_any_type)
     318   [ #  #  #  #  :          0 :                 if (!jl_is_concrete_type(sparam_val) || !jl_is_immutable(sparam_val))
                   #  # ]
     319                 :          0 :                     sparam_val = NULL;
     320                 :          0 :             nval[i + 1] = (void*)sparam_val;
     321                 :            :         }
     322                 :            :         int permanent =
     323                 :       4380 :             (result_type == jl_voidpointer_type) ||
     324   [ +  -  +  - ]:       4380 :             jl_is_concrete_type(fobj) ||
     325         [ +  + ]:       2190 :             (((jl_datatype_t*)jl_typeof(fobj))->instance == fobj);
     326         [ +  + ]:       2190 :         if (jl_is_unionall(fobj)) {
     327                 :         32 :             jl_value_t *uw = jl_unwrap_unionall(fobj);
     328   [ +  -  +  + ]:         32 :             if (jl_is_datatype(uw) && ((jl_datatype_t*)uw)->name->wrapper == fobj)
     329                 :          2 :                 permanent = true;
     330                 :            :         }
     331         [ +  + ]:       2190 :         if (permanent) {
     332                 :         14 :             result = jl_gc_permobj(sizeof(jl_taggedvalue_t) + jl_datatype_size(result_type), result_type);
     333                 :         14 :             memset(result, 0, jl_datatype_size(result_type));
     334                 :            :         }
     335                 :            :         else {
     336                 :       2176 :             result = jl_new_struct_uninit(result_type);
     337                 :            :         }
     338         [ +  - ]:       2186 :         if (result_type != jl_voidpointer_type) {
     339         [ -  + ]:       2186 :             assert(jl_datatype_size(result_type) == sizeof(void*) * 4);
     340                 :       2186 :             ((void**)result)[1] = (void*)fobj;
     341                 :            :         }
     342         [ +  + ]:       2186 :         if (!permanent) {
     343                 :       2172 :             jl_task_t *ct = jl_current_task;
     344                 :       2172 :             jl_gc_add_ptr_finalizer(ct->ptls, result, (void*)(uintptr_t)&trampoline_deleter);
     345                 :       2170 :             ((void**)result)[2] = (void*)cache;
     346                 :       2170 :             ((void**)result)[3] = (void*)nval;
     347                 :            :         }
     348                 :            :     }
     349         [ #  # ]:          0 :     JL_CATCH {
     350                 :          0 :         free(nval);
     351                 :          0 :         jl_rethrow();
     352                 :            :     }
     353                 :       2184 :     uv_mutex_lock(&trampoline_lock);
     354                 :       2195 :     tramp = trampoline_alloc();
     355                 :       2195 :     ((void**)result)[0] = tramp;
     356                 :       2195 :     tramp = init_trampoline(tramp, nval);
     357                 :       2195 :     ptrhash_put(cache, (void*)fobj, result);
     358                 :       2195 :     uv_mutex_unlock(&trampoline_lock);
     359                 :       2195 :     return result;
     360                 :            : }
     361                 :            : JL_GCC_IGNORE_STOP
     362                 :            : 
     363                 :        573 : void jl_init_runtime_ccall(void)
     364                 :            : {
     365                 :        573 :     JL_MUTEX_INIT(&libmap_lock);
     366                 :        573 :     uv_mutex_init(&trampoline_lock);
     367                 :        573 : }

Generated by: LCOV version 1.14