Ejemplo n.º 1
0
/* 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);
    }
}
Ejemplo n.º 2
0
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);
    });
Ejemplo n.º 3
0
/* 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);
}
Ejemplo n.º 4
0
Archivo: sc.c Proyecto: etheleon/MoarVM
/* 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);
        });
    });
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
/* 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);
}
Ejemplo n.º 7
0
/* 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;
            }
        });
    });
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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;
}