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; }
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; }
/* Finishes up reading and exploding of a frame. */ void MVM_bytecode_finish_frame(MVMThreadContext *tc, MVMCompUnit *cu, MVMStaticFrame *sf, MVMint32 dump_only) { MVMuint32 j; MVMuint8 *pos; MVMuint16 slvs; /* Ensure we've not already done this. */ if (sf->body.fully_deserialized) return; /* Acquire the update mutex on the CompUnit. */ MVM_reentrantmutex_lock(tc, (MVMReentrantMutex *)cu->body.update_mutex); /* Ensure no other thread has done this for us in the mean time. */ if (sf->body.fully_deserialized) { MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.update_mutex); return; } /* Locate start of frame body. */ pos = sf->body.frame_data_pos; /* Get the number of static lex values we'll need to apply. */ slvs = read_int16(pos, 40); /* Skip past header. */ pos += FRAME_HEADER_SIZE; /* Read the local types. */ if (sf->body.num_locals) { sf->body.local_types = MVM_malloc(sizeof(MVMuint16) * sf->body.num_locals); for (j = 0; j < sf->body.num_locals; j++) sf->body.local_types[j] = read_int16(pos, 2 * j); pos += 2 * sf->body.num_locals; } /* Read the lexical types. */ if (sf->body.num_lexicals) { /* Allocate names hash and types list. */ sf->body.lexical_types = MVM_malloc(sizeof(MVMuint16) * sf->body.num_lexicals); /* Read in data. */ if (sf->body.num_lexicals) { sf->body.lexical_names_list = MVM_malloc(sizeof(MVMLexicalRegistry *) * sf->body.num_lexicals); } for (j = 0; j < sf->body.num_lexicals; j++) { MVMString *name = get_heap_string(tc, cu, NULL, pos, 6 * j + 2); MVMLexicalRegistry *entry = MVM_calloc(1, sizeof(MVMLexicalRegistry)); MVM_ASSIGN_REF(tc, &(sf->common.header), entry->key, name); sf->body.lexical_names_list[j] = entry; entry->value = j; sf->body.lexical_types[j] = read_int16(pos, 6 * j); MVM_string_flatten(tc, name); MVM_HASH_BIND(tc, sf->body.lexical_names, name, entry) } pos += 6 * sf->body.num_lexicals; }
/* Get a representation's ID from its name. Note that the IDs may change so * it's best not to store references to them in e.g. the bytecode stream. */ MVMuint32 MVM_repr_name_to_id(MVMThreadContext *tc, MVMString *name) { MVMREPRHashEntry *entry; MVM_string_flatten(tc, name); MVM_HASH_GET(tc, tc->instance->repr_name_to_id_hash, name, entry) if (entry == NULL) MVM_exception_throw_adhoc(tc, "Lookup by name of unknown REPR: %s", MVM_string_utf8_encode_C_string(tc, name)); return entry->value; }
static MVMReprRegistry * find_repr_by_name(MVMThreadContext *tc, MVMString *name) { MVMReprRegistry *entry; MVM_string_flatten(tc, name); MVM_HASH_GET(tc, tc->instance->repr_hash, name, entry) if (entry == NULL) MVM_exception_throw_adhoc(tc, "Lookup by name of unknown REPR: %s", MVM_string_ascii_encode_any(tc, name)); return entry; }
/* 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; }
/* Registers a representation. */ static void register_repr(MVMThreadContext *tc, const MVMREPROps *repr, MVMString *name) { MVMReprRegistry *entry; if (!name) name = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, repr->name); /* Fill a registry entry. */ entry = malloc(sizeof(MVMReprRegistry)); entry->name = name; entry->repr = repr; /* Name should become a permanent GC root. */ MVM_gc_root_add_permanent(tc, (MVMCollectable **)&entry->name); /* Enter into registry. */ tc->instance->repr_list[repr->ID] = entry; MVM_string_flatten(tc, name); MVM_HASH_BIND(tc, tc->instance->repr_hash, name, entry); }
/* 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; }
/* Registers a representation. It this is ever made public, it should first be * made thread-safe, and it should check if the name is already registered. */ static void register_repr(MVMThreadContext *tc, MVMString *name, MVMREPROps *repr) { /* Allocate an ID. */ MVMuint32 ID = tc->instance->num_reprs; /* Allocate a hash entry for the name-to-ID. Could one day be unified with MVMREPROps, I suppose. */ MVMREPRHashEntry *entry = calloc(sizeof(MVMREPRHashEntry), 1); entry->value = ID; /* Bump the repr count */ tc->instance->num_reprs++; /* Stash ID and name. */ repr->ID = ID; repr->name = name; /* Name should become a permanent GC root. */ MVM_gc_root_add_permanent(tc, (MVMCollectable **)&repr->name); /* Enter into registry. */ if (tc->instance->repr_registry) tc->instance->repr_registry = realloc(tc->instance->repr_registry, tc->instance->num_reprs * sizeof(MVMREPROps *)); else tc->instance->repr_registry = malloc(tc->instance->num_reprs * sizeof(MVMREPROps *)); tc->instance->repr_registry[ID] = repr; MVM_string_flatten(tc, name); MVM_HASH_BIND(tc, tc->instance->repr_name_to_id_hash, name, entry); /* Add default "not implemented" function table implementations. */ if (!repr->elems) repr->elems = default_elems; if (!repr->attr_funcs) add_default_attr_funcs(tc, repr); if (!repr->box_funcs) add_default_box_funcs(tc, repr); if (!repr->pos_funcs) add_default_pos_funcs(tc, repr); if (!repr->ass_funcs) add_default_ass_funcs(tc, repr); }
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); }); });
/* 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) { MVMObject *sc; MVMCompUnit *cur_cu; /* Allocate. */ MVMROOT(tc, handle, { sc = REPR(tc->instance->SCRef)->allocate(tc, STABLE(tc->instance->SCRef)); MVMROOT(tc, sc, { REPR(sc)->initialize(tc, STABLE(sc), sc, OBJECT_BODY(sc)); /* Set handle. */ MVM_ASSIGN_REF(tc, sc, ((MVMSerializationContext *)sc)->body->handle, handle); /* Add to weak lookup hash. */ if (apr_thread_mutex_lock(tc->instance->mutex_sc_weakhash) != APR_SUCCESS) MVM_exception_throw_adhoc(tc, "Unable to lock SC weakhash"); MVM_string_flatten(tc, handle); MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, ((MVMSerializationContext *)sc)->body); if (apr_thread_mutex_unlock(tc->instance->mutex_sc_weakhash) != APR_SUCCESS) MVM_exception_throw_adhoc(tc, "Unable to unlock SC weakhash"); /* Visit compilation units that need this SC and resolve it. */ cur_cu = tc->instance->head_compunit; while (cur_cu) { if (cur_cu->scs_to_resolve) { MVMuint32 i; for (i = 0; i < cur_cu->num_scs; i++) { MVMString *res = cur_cu->scs_to_resolve[i]; if (res && MVM_string_equal(tc, res, handle)) { cur_cu->scs[i] = (MVMSerializationContext *)sc; cur_cu->scs_to_resolve[i] = NULL; break; } } } cur_cu = cur_cu->next_compunit; } }); });
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; }