int MVM_dll_free(MVMThreadContext *tc, MVMString *name) { MVMDLLRegistry *entry; uv_mutex_lock(&tc->instance->mutex_dll_registry); MVM_string_flatten(tc, name); MVM_HASH_GET(tc, tc->instance->dll_registry, name, entry); if (!entry) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc(tc, "cannot free non-existent library"); } /* already freed */ if (!entry->lib) return 0; if (entry->refcount > 0) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc(tc, "cannot free in-use library"); } dlFreeLibrary(entry->lib); entry->lib = NULL; uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 1; }
int MVM_repr_register_dynamic_repr(MVMThreadContext *tc, MVMREPROps *repr) { MVMReprRegistry *entry; MVMString *name; uv_mutex_lock(&tc->instance->mutex_repr_registry); name = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, repr->name); MVM_string_flatten(tc, name); MVM_HASH_GET(tc, tc->instance->repr_hash, name, entry); if (entry) { uv_mutex_unlock(&tc->instance->mutex_repr_registry); return 0; } if (!(tc->instance->num_reprs < MVM_REPR_MAX_COUNT)) { uv_mutex_unlock(&tc->instance->mutex_repr_registry); MVM_exception_throw_adhoc(tc, "Cannot register more than %u representations", MVM_REPR_MAX_COUNT); } repr->ID = tc->instance->num_reprs++; register_repr(tc, repr, name); uv_mutex_unlock(&tc->instance->mutex_repr_registry); return 1; }
/* Loads the SC dependencies list. */ static void deserialize_sc_deps(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { MVMCompUnitBody *cu_body = &cu->body; MVMuint32 i, sh_idx; MVMuint8 *pos; /* Allocate SC lists in compilation unit. */ cu_body->scs = MVM_malloc(rs->expected_scs * sizeof(MVMSerializationContext *)); cu_body->scs_to_resolve = MVM_malloc(rs->expected_scs * sizeof(MVMSerializationContextBody *)); cu_body->sc_handle_idxs = MVM_malloc(rs->expected_scs * sizeof(MVMint32)); cu_body->num_scs = rs->expected_scs; /* Resolve all the things. */ pos = rs->sc_seg; for (i = 0; i < rs->expected_scs; i++) { MVMSerializationContextBody *scb; MVMString *handle; /* Grab string heap index. */ ensure_can_read(tc, cu, rs, pos, 4); sh_idx = read_int32(pos, 0); pos += 4; /* Resolve to string. */ if (sh_idx >= cu_body->num_strings) { cleanup_all(tc, rs); MVM_exception_throw_adhoc(tc, "String heap index beyond end of string heap"); } cu_body->sc_handle_idxs[i] = sh_idx; handle = MVM_cu_string(tc, cu, sh_idx); /* See if we can resolve it. */ uv_mutex_lock(&tc->instance->mutex_sc_weakhash); MVM_string_flatten(tc, handle); MVM_HASH_GET(tc, tc->instance->sc_weakhash, handle, scb); if (scb && scb->sc) { cu_body->scs_to_resolve[i] = NULL; MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->scs[i], scb->sc); } else { if (!scb) { scb = MVM_calloc(1, sizeof(MVMSerializationContextBody)); scb->handle = handle; MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, scb); MVM_sc_add_all_scs_entry(tc, scb); } cu_body->scs_to_resolve[i] = scb; cu_body->scs[i] = NULL; } uv_mutex_unlock(&tc->instance->mutex_sc_weakhash); } }
void MVM_load_bytecode(MVMThreadContext *tc, MVMString *filename) { MVMCompUnit *cu; MVMLoadedCompUnitName *loaded_name; /* Work out actual filename to use, taking --libpath into account. */ filename = MVM_file_in_libpath(tc, filename); /* See if we already loaded this. */ uv_mutex_lock(&tc->instance->mutex_loaded_compunits); MVM_string_flatten(tc, filename); MVM_HASH_GET(tc, tc->instance->loaded_compunits, filename, loaded_name); if (loaded_name) { /* already loaded */ uv_mutex_unlock(&tc->instance->mutex_loaded_compunits); return; } /* Otherwise, load from disk. */ MVMROOT(tc, filename, { char *c_filename = MVM_string_utf8_c8_encode_C_string(tc, filename); /* XXX any exception from MVM_cu_map_from_file needs to be handled * and c_filename needs to be freed */ cu = MVM_cu_map_from_file(tc, c_filename); MVM_free(c_filename); cu->body.filename = filename; /* If there's a deserialization frame, need to run that. */ if (cu->body.deserialize_frame) { /* Set up special return to delegate to running the load frame, * if any. */ tc->cur_frame->return_value = NULL; tc->cur_frame->return_type = MVM_RETURN_VOID; tc->cur_frame->special_return = run_load; tc->cur_frame->special_return_data = cu; tc->cur_frame->mark_special_return_data = mark_sr_data; /* Invoke the deserialization frame and return to the runloop. */ MVM_frame_invoke(tc, cu->body.deserialize_frame, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS), NULL, NULL, NULL, -1); } else { /* No deserialize frame, so do load frame instead. */ run_load(tc, cu); } loaded_name = MVM_calloc(1, sizeof(MVMLoadedCompUnitName)); loaded_name->filename = filename; MVM_HASH_BIND(tc, tc->instance->loaded_compunits, filename, loaded_name); });
MVMObject * MVM_dll_find_symbol(MVMThreadContext *tc, MVMString *lib, MVMString *sym) { MVMDLLRegistry *entry; MVMDLLSym *obj; char *csym; void *address; uv_mutex_lock(&tc->instance->mutex_dll_registry); MVM_string_flatten(tc, lib); MVM_HASH_GET(tc, tc->instance->dll_registry, lib, entry); if (!entry) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc(tc, "cannot find symbol in non-existent library"); } if (!entry->lib) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc(tc, "cannot find symbol in unloaded library"); } csym = MVM_string_utf8_encode_C_string(tc, sym); address = dlFindSymbol(entry->lib, csym); free(csym); if (!address) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); return NULL; } obj = (MVMDLLSym *)MVM_repr_alloc_init(tc, tc->instance->raw_types.RawDLLSym); obj->body.address = address; obj->body.dll = entry; entry->refcount++; uv_mutex_unlock(&tc->instance->mutex_dll_registry); return (MVMObject *)obj; }
/* Creates a new serialization context with the specified handle. If any * compilation units are waiting for an SC with this handle, removes it from * their to-resolve list after installing itself in the appropriate slot. */ MVMObject * MVM_sc_create(MVMThreadContext *tc, MVMString *handle) { MVMSerializationContext *sc; MVMSerializationContextBody *scb; /* Allocate. */ MVMROOT(tc, handle, { sc = (MVMSerializationContext *)REPR(tc->instance->SCRef)->allocate(tc, STABLE(tc->instance->SCRef)); MVMROOT(tc, sc, { /* Add to weak lookup hash. */ uv_mutex_lock(&tc->instance->mutex_sc_weakhash); MVM_string_flatten(tc, handle); MVM_HASH_GET(tc, tc->instance->sc_weakhash, handle, scb); if (!scb) { sc->body = scb = calloc(1, sizeof(MVMSerializationContextBody)); MVM_ASSIGN_REF(tc, (MVMObject *)sc, scb->handle, handle); MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, scb); /* Calling repr_init will allocate, BUT if it does so, and we * get unlucky, the GC will try to acquire mutex_sc_weakhash. * This deadlocks. Thus, we force allocation in gen2, which * can never trigger GC. Note that releasing the mutex early * is not a good way to fix this, as it leaves a race to * test/set scb->sc (between the line doing it in this block, * and in the else clauses beneath it). */ MVM_gc_allocate_gen2_default_set(tc); MVM_repr_init(tc, (MVMObject *)sc); MVM_gc_allocate_gen2_default_clear(tc); scb->sc = sc; } else if (scb->sc) { /* we lost a race to create it! */ sc = scb->sc; } else { scb->sc = sc; sc->body = scb; MVM_ASSIGN_REF(tc, sc, scb->handle, handle); MVM_repr_init(tc, (MVMObject *)sc); } uv_mutex_unlock(&tc->instance->mutex_sc_weakhash); }); });
int MVM_dll_load(MVMThreadContext *tc, MVMString *name, MVMString *path) { MVMDLLRegistry *entry; char *cpath; DLLib *lib; uv_mutex_lock(&tc->instance->mutex_dll_registry); MVM_string_flatten(tc, name); MVM_HASH_GET(tc, tc->instance->dll_registry, name, entry); /* already loaded */ if (entry && entry->lib) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 0; } cpath = MVM_string_utf8_encode_C_string(tc, path); lib = dlLoadLibrary(cpath); if (!lib) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc(tc, "failed to load library '%s'", cpath); } free(cpath); if (!entry) { entry = malloc(sizeof *entry); entry->name = name; entry->refcount = 0; MVM_gc_root_add_permanent(tc, (MVMCollectable **)&entry->name); MVM_HASH_BIND(tc, tc->instance->dll_registry, name, entry); } entry->lib = lib; uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 1; }
int MVM_dll_load(MVMThreadContext *tc, MVMString *name, MVMString *path) { MVMDLLRegistry *entry; char *cpath; DLLib *lib; MVM_string_flatten(tc, name); uv_mutex_lock(&tc->instance->mutex_dll_registry); MVM_HASH_GET(tc, tc->instance->dll_registry, name, entry); /* already loaded */ if (entry && entry->lib) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 0; } MVMROOT(tc, name, { MVMROOT(tc, path, { path = MVM_file_in_libpath(tc, path); }); });
static void * unmarshal_callback(MVMThreadContext *tc, MVMObject *callback, MVMObject *sig_info) { MVMNativeCallbackCacheHead *callback_data_head = NULL; MVMNativeCallback **callback_data_handle; MVMString *cuid; if (!IS_CONCRETE(callback)) return NULL; /* Try to locate existing cached callback info. */ callback = MVM_frame_find_invokee(tc, callback, NULL); cuid = ((MVMCode *)callback)->body.sf->body.cuuid; MVM_string_flatten(tc, cuid); MVM_HASH_GET(tc, tc->native_callback_cache, cuid, callback_data_head); if (!callback_data_head) { callback_data_head = MVM_malloc(sizeof(MVMNativeCallbackCacheHead)); callback_data_head->head = NULL; MVM_HASH_BIND(tc, tc->native_callback_cache, cuid, callback_data_head); } callback_data_handle = &(callback_data_head->head); while (*callback_data_handle) { if ((*callback_data_handle)->target == callback) /* found it, break */ break; callback_data_handle = &((*callback_data_handle)->next); } if (!*callback_data_handle) { /* First, build the MVMNativeCallback */ MVMCallsite *cs; char *signature; MVMObject *typehash; MVMint64 num_info, i; MVMNativeCallback *callback_data; num_info = MVM_repr_elems(tc, sig_info); callback_data = MVM_malloc(sizeof(MVMNativeCallback)); callback_data->num_types = num_info; callback_data->typeinfos = MVM_malloc(num_info * sizeof(MVMint16)); callback_data->types = MVM_malloc(num_info * sizeof(MVMObject *)); callback_data->next = NULL; /* A dyncall signature looks like this: xxx)x * Argument types before the ) and return type after it. Thus, * num_info+1 must be NULL (zero-terminated string) and num_info-1 * must be the ). */ signature = MVM_malloc(num_info + 2); signature[num_info + 1] = '\0'; signature[num_info - 1] = ')'; /* We'll also build up a MoarVM callsite as we go. */ cs = MVM_malloc(sizeof(MVMCallsite)); cs->arg_flags = MVM_malloc(num_info * sizeof(MVMCallsiteEntry)); cs->arg_count = num_info - 1; cs->num_pos = num_info - 1; cs->has_flattening = 0; cs->is_interned = 0; cs->with_invocant = NULL; typehash = MVM_repr_at_pos_o(tc, sig_info, 0); callback_data->types[0] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[0] = MVM_nativecall_get_arg_type(tc, typehash, 1); signature[num_info] = get_signature_char(callback_data->typeinfos[0]); for (i = 1; i < num_info; i++) { typehash = MVM_repr_at_pos_o(tc, sig_info, i); callback_data->types[i] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[i] = MVM_nativecall_get_arg_type(tc, typehash, 0) & ~MVM_NATIVECALL_ARG_FREE_STR; signature[i - 1] = get_signature_char(callback_data->typeinfos[i]); switch (callback_data->typeinfos[i] & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: case MVM_NATIVECALL_ARG_SHORT: case MVM_NATIVECALL_ARG_INT: case MVM_NATIVECALL_ARG_LONG: case MVM_NATIVECALL_ARG_LONGLONG: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_UCHAR: case MVM_NATIVECALL_ARG_USHORT: case MVM_NATIVECALL_ARG_UINT: case MVM_NATIVECALL_ARG_ULONG: case MVM_NATIVECALL_ARG_ULONGLONG: /* TODO: should probably be UINT, when we can support that. */ cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_FLOAT: case MVM_NATIVECALL_ARG_DOUBLE: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_NUM; break; default: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_OBJ; break; } } MVM_callsite_try_intern(tc, &cs); callback_data->tc = tc; callback_data->cs = cs; callback_data->target = callback; callback_data->cb = dcbNewCallback(signature, (DCCallbackHandler *)&callback_handler, callback_data); /* Now insert the MVMCallback into the linked list. */ *callback_data_handle = callback_data; MVM_free(signature); } return (*callback_data_handle)->cb; }
static void * unmarshal_callback(MVMThreadContext *tc, MVMObject *callback, MVMObject *sig_info) { MVMNativeCallbackCacheHead *callback_data_head = NULL; MVMNativeCallback **callback_data_handle; MVMString *cuid; if (!IS_CONCRETE(callback)) return NULL; /* Try to locate existing cached callback info. */ callback = MVM_frame_find_invokee(tc, callback, NULL); cuid = ((MVMCode *)callback)->body.sf->body.cuuid; MVM_HASH_GET(tc, tc->native_callback_cache, cuid, callback_data_head); if (!callback_data_head) { callback_data_head = MVM_malloc(sizeof(MVMNativeCallbackCacheHead)); callback_data_head->head = NULL; MVM_HASH_BIND(tc, tc->native_callback_cache, cuid, callback_data_head); } callback_data_handle = &(callback_data_head->head); while (*callback_data_handle) { if ((*callback_data_handle)->target == callback) /* found it, break */ break; callback_data_handle = &((*callback_data_handle)->next); } if (!*callback_data_handle) { /* First, build the MVMNativeCallback */ MVMCallsite *cs; MVMObject *typehash; MVMint64 num_info, i; MVMNativeCallback *callback_data; /* cb is a piece of executable memory we obtain from libffi. */ void *cb; ffi_cif *cif; ffi_closure *closure; ffi_status status; num_info = MVM_repr_elems(tc, sig_info); /* We'll also build up a MoarVM callsite as we go. */ cs = MVM_calloc(1, sizeof(MVMCallsite)); cs->flag_count = num_info - 1; cs->arg_flags = MVM_malloc(cs->flag_count * sizeof(MVMCallsiteEntry)); cs->arg_count = num_info - 1; cs->num_pos = num_info - 1; cs->has_flattening = 0; cs->is_interned = 0; cs->with_invocant = NULL; callback_data = MVM_malloc(sizeof(MVMNativeCallback)); callback_data->num_types = num_info; callback_data->typeinfos = MVM_malloc(num_info * sizeof(MVMint16)); callback_data->types = MVM_malloc(num_info * sizeof(MVMObject *)); callback_data->next = NULL; cif = (ffi_cif *)MVM_malloc(sizeof(ffi_cif)); callback_data->convention = FFI_DEFAULT_ABI; callback_data->ffi_arg_types = MVM_malloc(sizeof(ffi_type *) * (cs->arg_count ? cs->arg_count : 1)); /* Collect information about the return type. */ typehash = MVM_repr_at_pos_o(tc, sig_info, 0); callback_data->types[0] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[0] = MVM_nativecall_get_arg_type(tc, typehash, 1); callback_data->ffi_ret_type = MVM_nativecall_get_ffi_type(tc, callback_data->typeinfos[0]); for (i = 1; i < num_info; i++) { typehash = MVM_repr_at_pos_o(tc, sig_info, i); callback_data->types[i] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[i] = MVM_nativecall_get_arg_type(tc, typehash, 0) & ~MVM_NATIVECALL_ARG_FREE_STR; callback_data->ffi_arg_types[i - 1] = MVM_nativecall_get_ffi_type(tc, callback_data->typeinfos[i]); switch (callback_data->typeinfos[i] & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: case MVM_NATIVECALL_ARG_SHORT: case MVM_NATIVECALL_ARG_INT: case MVM_NATIVECALL_ARG_LONG: case MVM_NATIVECALL_ARG_LONGLONG: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_UCHAR: case MVM_NATIVECALL_ARG_USHORT: case MVM_NATIVECALL_ARG_UINT: case MVM_NATIVECALL_ARG_ULONG: case MVM_NATIVECALL_ARG_ULONGLONG: /* TODO: should probably be UINT, when we can support that. */ cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_FLOAT: case MVM_NATIVECALL_ARG_DOUBLE: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_NUM; break; default: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_OBJ; break; } } MVM_callsite_try_intern(tc, &cs); callback_data->instance = tc->instance; callback_data->cs = cs; callback_data->target = callback; status = ffi_prep_cif(cif, callback_data->convention, (unsigned int)cs->arg_count, callback_data->ffi_ret_type, callback_data->ffi_arg_types); closure = ffi_closure_alloc(sizeof(ffi_closure), &cb); if (!closure) MVM_panic(1, "Unable to allocate memory for callback closure"); ffi_prep_closure_loc(closure, cif, callback_handler, callback_data, cb); callback_data->cb = cb; /* Now insert the MVMCallback into the linked list. */ *callback_data_handle = callback_data; } return (*callback_data_handle)->cb; }