/* Takes a stub object that existed before we had bootstrapped things and * gives it a meta-object. */ static void add_meta_object(MVMThreadContext *tc, MVMObject *type_obj, char *name) { MVMObject *meta_obj; MVMString *name_str; /* Create meta-object. */ meta_obj = MVM_repr_alloc_init(tc, STABLE(tc->instance->KnowHOW)->HOW); MVMROOT(tc, meta_obj, { /* Put it in place. */ MVM_ASSIGN_REF(tc, STABLE(type_obj), STABLE(type_obj)->HOW, meta_obj); /* Set name. */ name_str = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, name); MVM_ASSIGN_REF(tc, meta_obj, ((MVMKnowHOWREPR *)meta_obj)->body.name, name_str); });
/* Initializes a new thread context. Note that this doesn't set up a * thread itself, it just creates the data structure that exists in * MoarVM per thread. */ MVMThreadContext * MVM_tc_create(MVMInstance *instance) { MVMThreadContext *tc = calloc(1, sizeof(MVMThreadContext)); /* Associate with VM instance. */ tc->instance = instance; /* Set up GC nursery. */ tc->nursery_fromspace = calloc(1, MVM_NURSERY_SIZE); tc->nursery_tospace = calloc(1, MVM_NURSERY_SIZE); tc->nursery_alloc = tc->nursery_tospace; tc->nursery_alloc_limit = (char *)tc->nursery_alloc + MVM_NURSERY_SIZE; /* Set up temporary root handling. */ tc->num_temproots = 0; tc->alloc_temproots = 16; tc->temproots = malloc(sizeof(MVMCollectable **) * tc->alloc_temproots); /* Set up intergenerational root handling. */ tc->num_gen2roots = 0; tc->alloc_gen2roots = 64; tc->gen2roots = malloc(sizeof(MVMCollectable *) * tc->alloc_gen2roots); /* Set up the second generation allocator. */ tc->gen2 = MVM_gc_gen2_create(instance); /* Set up table of per-static-frame chains. */ /* XXX For non-first threads, make them start with the size of the main thread's table. or, look into lazily initializing this. */ tc->frame_pool_table_size = MVMInitialFramePoolTableSize; tc->frame_pool_table = calloc(MVMInitialFramePoolTableSize, sizeof(MVMFrame *)); tc->loop = instance->default_loop ? uv_loop_new() : uv_default_loop(); /* Create a CallCapture for usecapture instructions in this thread (needs * special handling in initial thread as this runs before bootstrap). */ if (instance->CallCapture) tc->cur_usecapture = MVM_repr_alloc_init(tc, instance->CallCapture); /* Initialize random number generator state. */ MVM_proc_seed(tc, (MVM_platform_now() / 10000) * MVM_proc_getpid(tc)); #if MVM_HLL_PROFILE_CALLS #define PROFILE_INITIAL_SIZE (1 << 29) tc->profile_data_size = PROFILE_INITIAL_SIZE; tc->profile_data = malloc(sizeof(MVMProfileRecord) * PROFILE_INITIAL_SIZE); tc->profile_index = 0; #endif return tc; }
/* Read handler. */ static void on_read(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { ReadInfo *ri = (ReadInfo *)handle->data; MVMThreadContext *tc = ri->tc; MVMObject *arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); MVMAsyncTask *t = (MVMAsyncTask *)MVM_repr_at_pos_o(tc, tc->instance->event_loop_active, ri->work_idx); MVM_repr_push_o(tc, arr, t->body.schedulee); if (nread > 0) { MVMROOT(tc, t, { MVMROOT(tc, arr, { /* Push the sequence number. */ MVMObject *seq_boxed = MVM_repr_box_int(tc, tc->instance->boot_types.BOOTInt, ri->seq_number++); MVM_repr_push_o(tc, arr, seq_boxed); /* Either need to produce a buffer or decode characters. */ if (ri->ds) { MVMString *str; MVMObject *boxed_str; MVM_string_decodestream_add_bytes(tc, ri->ds, buf->base, nread); str = MVM_string_decodestream_get_all(tc, ri->ds); boxed_str = MVM_repr_box_str(tc, tc->instance->boot_types.BOOTStr, str); MVM_repr_push_o(tc, arr, boxed_str); } else { MVMArray *res_buf = (MVMArray *)MVM_repr_alloc_init(tc, ri->buf_type); res_buf->body.slots.i8 = buf->base; res_buf->body.start = 0; res_buf->body.ssize = nread; res_buf->body.elems = nread; MVM_repr_push_o(tc, arr, (MVMObject *)res_buf); } /* Finally, no error. */ MVM_repr_push_o(tc, arr, tc->instance->boot_types.BOOTStr); }); });
/* Sets the passed thread context's thread up so that we'll run a finalize * handler on it in the near future. */ static void finalize_handler_caller(MVMThreadContext *tc, void *sr_data) { MVMObject *handler = MVM_hll_current(tc)->finalize_handler; if (handler) { /* Drain the finalizing queue to an array. */ MVMObject *drain = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); while (tc->num_finalizing > 0) MVM_repr_push_o(tc, drain, tc->finalizing[--tc->num_finalizing]); /* Invoke the handler. */ handler = MVM_frame_find_invokee(tc, handler, NULL); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG)); tc->cur_frame->args[0].o = drain; STABLE(handler)->invoke(tc, handler, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG), tc->cur_frame->args); } }
/* Takes an object, which must be of VMArray representation and holding * 32-bit integers. Treats them as Unicode codepoints, normalizes them at * Grapheme level, and returns the resulting NFG string. */ MVMString * MVM_unicode_codepoints_to_nfg_string(MVMThreadContext *tc, MVMObject *codes) { MVMNormalizer norm; MVMCodepoint *input; MVMGrapheme32 *result; MVMint64 input_pos, input_codes, result_pos, result_alloc; MVMint32 ready; MVMString *str; /* Get input array; if it's empty, we're done already. */ assert_codepoint_array(tc, codes, "Code points to string input must be native array of 32-bit integers"); input = (MVMCodepoint *)((MVMArray *)codes)->body.slots.u32 + ((MVMArray *)codes)->body.start; input_codes = ((MVMArray *)codes)->body.elems; if (input_codes == 0) return tc->instance->str_consts.empty; /* Guess output size based on input size. */ result_alloc = input_codes; result = MVM_malloc(result_alloc * sizeof(MVMCodepoint)); /* Perform normalization at grapheme level. */ MVM_unicode_normalizer_init(tc, &norm, MVM_NORMALIZE_NFG); input_pos = 0; result_pos = 0; while (input_pos < input_codes) { MVMGrapheme32 g; ready = MVM_unicode_normalizer_process_codepoint_to_grapheme(tc, &norm, input[input_pos], &g); if (ready) { maybe_grow_result(&result, &result_alloc, result_pos + ready); result[result_pos++] = g; while (--ready > 0) result[result_pos++] = MVM_unicode_normalizer_get_grapheme(tc, &norm); } input_pos++; } MVM_unicode_normalizer_eof(tc, &norm); ready = MVM_unicode_normalizer_available(tc, &norm); maybe_grow_result(&result, &result_alloc, result_pos + ready); while (ready--) result[result_pos++] = MVM_unicode_normalizer_get_grapheme(tc, &norm); MVM_unicode_normalizer_cleanup(tc, &norm); /* Produce an MVMString of the result. */ str = (MVMString *)MVM_repr_alloc_init(tc, tc->instance->VMString); str->body.storage.blob_32 = result; str->body.storage_type = MVM_STRING_GRAPHEME_32; str->body.num_graphs = result_pos; return str; }
MVMObject * MVM_proc_getenvhash(MVMThreadContext *tc) { MVMInstance * const instance = tc->instance; MVMObject * env_hash; #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ #endif MVMuint32 pos = 0; MVMString *needle = MVM_string_ascii_decode(tc, instance->VMString, STR_WITH_LEN("=")); char *env; MVM_gc_root_temp_push(tc, (MVMCollectable **)&needle); env_hash = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_hash_type); MVM_gc_root_temp_push(tc, (MVMCollectable **)&env_hash); while ((env = environ[pos++]) != NULL) { #ifndef _WIN32 MVMString *str = MVM_string_utf8_c8_decode(tc, instance->VMString, env, strlen(env)); #else char * const _env = ANSIToUTF8(acp, env); MVMString *str = MVM_string_utf8_c8_decode(tc, instance->VMString, _env, strlen(_env)); #endif MVMuint32 index = MVM_string_index(tc, str, needle, 0); MVMString *key, *val; MVMObject *box; #ifdef _WIN32 MVM_free(_env); #endif MVM_gc_root_temp_push(tc, (MVMCollectable **)&str); key = MVM_string_substring(tc, str, 0, index); MVM_gc_root_temp_push(tc, (MVMCollectable **)&key); val = MVM_string_substring(tc, str, index + 1, -1); box = MVM_repr_box_str(tc, MVM_hll_current(tc)->str_box_type, val); MVM_repr_bind_key_o(tc, env_hash, key, box); MVM_gc_root_temp_pop_n(tc, 2); } MVM_gc_root_temp_pop_n(tc, 2); return env_hash; }
/* Completion handler for an asynchronous write. */ static void on_write(uv_write_t *req, int status) { SpawnWriteInfo *wi = (SpawnWriteInfo *)req->data; MVMThreadContext *tc = wi->tc; MVMObject *arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); MVMAsyncTask *t = (MVMAsyncTask *)MVM_repr_at_pos_o(tc, tc->instance->event_loop_active, wi->work_idx); MVM_repr_push_o(tc, arr, t->body.schedulee); if (status >= 0) { MVMROOT(tc, arr, { MVMROOT(tc, t, { MVMObject *bytes_box = MVM_repr_box_int(tc, tc->instance->boot_types.BOOTInt, wi->buf.len); MVM_repr_push_o(tc, arr, bytes_box); }); });
MVMObject * MVM_proc_getenvhash(MVMThreadContext *tc) { static MVMObject *env_hash; if (!env_hash) { #ifdef _WIN32 MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ #endif MVMuint32 pos = 0; MVMString *needle = MVM_decode_C_buffer_to_string(tc, tc->instance->VMString, "=", 1, MVM_encoding_type_ascii); char *env; MVM_gc_root_temp_push(tc, (MVMCollectable **)&needle); env_hash = MVM_repr_alloc_init(tc, tc->instance->boot_types->BOOTHash); MVM_gc_root_temp_push(tc, (MVMCollectable **)&env_hash); while ((env = environ[pos++]) != NULL) { #ifndef _WIN32 MVMString *str = MVM_decode_C_buffer_to_string(tc, tc->instance->VMString, env, strlen(env), MVM_encoding_type_utf8); #else char * const _env = ANSIToUTF8(acp, env); MVMString *str = MVM_decode_C_buffer_to_string(tc, tc->instance->VMString, _env, strlen(_env), MVM_encoding_type_utf8); #endif MVMuint32 index = MVM_string_index(tc, str, needle, 0); MVMString *key, *val; #ifdef _WIN32 free(_env); #endif MVM_gc_root_temp_push(tc, (MVMCollectable **)&str); key = MVM_string_substring(tc, str, 0, index); MVM_gc_root_temp_push(tc, (MVMCollectable **)&key); val = MVM_string_substring(tc, str, index + 1, -1); MVM_repr_bind_key_boxed(tc, env_hash, key, (MVMObject *)val); MVM_gc_root_temp_pop_n(tc, 2); } MVM_gc_root_temp_pop_n(tc, 2); } return env_hash; }
MVMObject * MVM_args_save_capture(MVMThreadContext *tc, MVMFrame *frame) { MVMObject *cc_obj; MVMROOT(tc, frame, { MVMCallCapture *cc = (MVMCallCapture *) (cc_obj = MVM_repr_alloc_init(tc, tc->instance->CallCapture)); /* Copy the arguments. */ MVMuint32 arg_size = frame->params.arg_count * sizeof(MVMRegister); MVMRegister *args = MVM_malloc(arg_size); memcpy(args, frame->params.args, arg_size); /* Set up the call capture, copying the callsite. */ cc->body.apc = (MVMArgProcContext *)MVM_calloc(1, sizeof(MVMArgProcContext)); MVM_args_proc_init(tc, cc->body.apc, MVM_args_copy_uninterned_callsite(tc, &frame->params), args); });
/* Takes a type and sets it up as a parametric type, provided it's OK to do so. */ void MVM_6model_parametric_setup(MVMThreadContext *tc, MVMObject *type, MVMObject *parameterizer) { MVMSTable *st = STABLE(type); /* Ensure that the type is not already parametric or parameterized. */ if (st->mode_flags & MVM_PARAMETRIC_TYPE) MVM_exception_throw_adhoc(tc, "This type is already parametric"); if (st->mode_flags & MVM_PARAMETERIZED_TYPE) MVM_exception_throw_adhoc(tc, "Cannot make a parameterized type also be parametric"); /* For now, we use a simple pairwise array, with parameters and the type * that is based on those parameters interleaved. It does make resolution * O(n), so we might like to do some hash in the future. */ MVMROOT(tc, st, { MVMROOT(tc, parameterizer, { MVMObject *lookup = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); MVM_ASSIGN_REF(tc, &(st->header), st->paramet.ric.lookup, lookup); }); });
MVMObject * MVM_platform_uname(MVMThreadContext *tc) { int error; uv_utsname_t uname; MVMObject *result; if ((error = uv_os_uname(&uname)) != 0) MVM_exception_throw_adhoc(tc, "Unable to uname: %s", uv_strerror(error)); MVMROOT(tc, result, { MVMString *sysname = MVM_string_utf8_decode(tc, tc->instance->VMString, uname.sysname, strlen((char *)uname.sysname)); MVMString *release = MVM_string_utf8_decode(tc, tc->instance->VMString, uname.release, strlen((char *)uname.release)); MVMString *version = MVM_string_utf8_decode(tc, tc->instance->VMString, uname.version, strlen((char *)uname.version)); MVMString *machine = MVM_string_utf8_decode(tc, tc->instance->VMString, uname.machine, strlen((char *)uname.machine)); result = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTStrArray); MVM_repr_bind_pos_s(tc, result, 0, sysname); MVM_repr_bind_pos_s(tc, result, 1, release); MVM_repr_bind_pos_s(tc, result, 2, version); MVM_repr_bind_pos_s(tc, result, 3, machine); });
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 timer. */ MVMObject * MVM_io_timer_create(MVMThreadContext *tc, MVMObject *queue, MVMObject *schedulee, MVMint64 timeout, MVMint64 repeat, MVMObject *async_type) { MVMAsyncTask *task; TimerInfo *timer_info; /* Validate REPRs. */ if (REPR(queue)->ID != MVM_REPR_ID_ConcBlockingQueue) MVM_exception_throw_adhoc(tc, "timer target queue must have ConcBlockingQueue REPR"); if (REPR(async_type)->ID != MVM_REPR_ID_MVMAsyncTask) MVM_exception_throw_adhoc(tc, "timer result type must have REPR AsyncTask"); /* Create async task handle. */ MVMROOT(tc, queue, { MVMROOT(tc, schedulee, { task = (MVMAsyncTask *)MVM_repr_alloc_init(tc, async_type); }); });
static MVMObject * socket_accept(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOSyncSocketData *data = (MVMIOSyncSocketData *)h->body.data; while (!data->accept_server) { if (tc->loop != data->ss.handle->loop) { MVM_exception_throw_adhoc(tc, "Tried to accept() on a socket from outside its originating thread"); } uv_ref((uv_handle_t *)data->ss.handle); MVM_gc_mark_thread_blocked(tc); uv_run(tc->loop, UV_RUN_DEFAULT); MVM_gc_mark_thread_unblocked(tc); } /* Check the accept worked out. */ if (data->accept_status < 0) { MVM_exception_throw_adhoc(tc, "Failed to listen: unknown error"); } else { uv_tcp_t *client = MVM_malloc(sizeof(uv_tcp_t)); uv_stream_t *server = data->accept_server; int r; uv_tcp_init(tc->loop, client); data->accept_server = NULL; if ((r = uv_accept(server, (uv_stream_t *)client)) == 0) { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOSyncSocketData * const data = MVM_calloc(1, sizeof(MVMIOSyncSocketData)); data->ss.handle = (uv_stream_t *)client; data->ss.encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->ss.sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } else { uv_close((uv_handle_t*)client, NULL); MVM_free(client); MVM_exception_throw_adhoc(tc, "Failed to accept: %s", uv_strerror(r)); } } }
void MVM_continuation_control(MVMThreadContext *tc, MVMint64 protect, MVMObject *tag, MVMObject *code, MVMRegister *res_reg) { MVMObject *cont; MVMCallsite *inv_arg_callsite; /* Hunt the tag on the stack; mark frames as being incorporated into a * continuation as we go to avoid a second pass. */ MVMFrame *jump_frame = tc->cur_frame; MVMFrame *root_frame = NULL; MVMContinuationTag *tag_record = NULL; while (jump_frame) { jump_frame->in_continuation = 1; tag_record = jump_frame->continuation_tags; while (tag_record) { if (MVM_is_null(tc, tag) || tag_record->tag == tag) break; tag_record = tag_record->next; } if (tag_record) break; root_frame = jump_frame; jump_frame = jump_frame->caller; } if (!tag_record) MVM_exception_throw_adhoc(tc, "No matching continuation reset found"); if (!root_frame) MVM_exception_throw_adhoc(tc, "No continuation root frame found"); /* Create continuation. */ MVMROOT(tc, code, { cont = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTContinuation); ((MVMContinuation *)cont)->body.top = MVM_frame_inc_ref(tc, tc->cur_frame); ((MVMContinuation *)cont)->body.addr = *tc->interp_cur_op; ((MVMContinuation *)cont)->body.res_reg = res_reg; ((MVMContinuation *)cont)->body.root = MVM_frame_inc_ref(tc, root_frame); if (tc->instance->profiling) ((MVMContinuation *)cont)->body.prof_cont = MVM_profile_log_continuation_control(tc, root_frame); });
MVMObject * MVM_proc_clargs(MVMThreadContext *tc) { MVMInstance *instance = tc->instance; if (!instance->clargs) { MVMObject *clargs = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type); MVMROOT(tc, clargs, { MVMint64 count; MVMString *prog_string = MVM_string_utf8_decode(tc, tc->instance->VMString, instance->prog_name, strlen(instance->prog_name)); MVM_repr_push_o(tc, clargs, MVM_repr_box_str(tc, tc->instance->boot_types->BOOTStr, prog_string)); for (count = 0; count < instance->num_clargs; count++) { char *raw = instance->raw_clargs[count]; MVMString *string = MVM_string_utf8_decode(tc, tc->instance->VMString, instance->raw_clargs[count], strlen(instance->raw_clargs[count])); MVM_repr_push_o(tc, clargs, MVM_repr_box_str(tc, tc->instance->boot_types->BOOTStr, string)); } });
MVMObject * collection_to_mvm_objects(MVMThreadContext *tc, MVMHeapSnapshotCollection *col) { MVMObject *results; /* Allocate in gen2, so as not to trigger GC. */ MVM_gc_allocate_gen2_default_set(tc); /* Top-level results is a hash. */ results = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_hash_type); MVM_repr_bind_key_o(tc, results, vmstr(tc, "strings"), string_heap_array(tc, col)); MVM_repr_bind_key_o(tc, results, vmstr(tc, "types"), types_str(tc, col)); MVM_repr_bind_key_o(tc, results, vmstr(tc, "static_frames"), static_frames_str(tc, col)); MVM_repr_bind_key_o(tc, results, vmstr(tc, "snapshots"), snapshots_to_mvm_objects(tc, col)); /* Switch off gen2 allocations now we're done. */ MVM_gc_allocate_gen2_default_clear(tc); return results; }
static void run_handler(MVMThreadContext *tc, LocatedHandler lh, MVMObject *ex_obj, MVMuint32 category, MVMObject *payload) { switch (lh.handler->action) { case MVM_EX_ACTION_GOTO_WITH_PAYLOAD: if (payload) tc->last_payload = payload; else if (ex_obj && ((MVMException *)ex_obj)->body.payload) tc->last_payload = ((MVMException *)ex_obj)->body.payload; else tc->last_payload = tc->instance->VMNull; /* Deliberate fallthrough to unwind below. */ case MVM_EX_ACTION_GOTO: if (lh.jit_handler) { void **labels = lh.frame->spesh_cand->jitcode->labels; MVMuint8 *pc = lh.frame->spesh_cand->jitcode->bytecode; lh.frame->jit_entry_label = labels[lh.jit_handler->goto_label]; MVM_frame_unwind_to(tc, lh.frame, pc, 0, NULL); } else { MVM_frame_unwind_to(tc, lh.frame, NULL, lh.handler->goto_offset, NULL); } break; case MVM_EX_ACTION_INVOKE: { /* Create active handler record. */ MVMActiveHandler *ah = MVM_malloc(sizeof(MVMActiveHandler)); MVMFrame *cur_frame = tc->cur_frame; MVMObject *handler_code; /* Ensure we have an exception object. */ if (ex_obj == NULL) { MVMROOT(tc, cur_frame, { MVMROOT(tc, lh.frame, { MVMROOT(tc, payload, { ex_obj = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTException); }); }); });
/* Creates a new lexotic. */ MVMObject * MVM_exception_newlexotic(MVMThreadContext *tc, MVMuint32 offset) { MVMLexotic *lexotic; /* Locate handler associated with the specified label. */ MVMStaticFrame *sf = tc->cur_frame->static_info; MVMFrameHandler *h = NULL; MVMuint32 i; for (i = 0; i < sf->num_handlers; i++) { if (sf->handlers[i].action == MVM_EX_ACTION_GOTO && sf->handlers[i].goto_offset == offset) { h = &sf->handlers[i]; break; } } if (h == NULL) MVM_exception_throw_adhoc(tc, "Label with no handler passed to newlexotic"); /* Allocate lexotic object and set it up. */ lexotic = (MVMLexotic *)MVM_repr_alloc_init(tc, tc->instance->Lexotic); lexotic->body.handler = h; lexotic->body.frame = MVM_frame_inc_ref(tc, tc->cur_frame); return (MVMObject *)lexotic; }
/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_encode_C_string(tc, filename); char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); uv_fs_t req; uv_file fd; /* Resolve mode description to flags. */ int flag; if (0 == strcmp("r", fmode)) flag = O_RDONLY; else if (0 == strcmp("w", fmode)) flag = O_CREAT| O_WRONLY | O_TRUNC; else if (0 == strcmp("wa", fmode)) flag = O_CREAT | O_WRONLY | O_APPEND; else { MVM_free(fname); MVM_exception_throw_adhoc(tc, "Invalid open mode: %s", fmode); } MVM_free(fmode); /* Try to open the file. */ if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) { MVM_exception_throw_adhoc(tc, "Failed to open file %s: %s", fname, uv_strerror(req.result)); } /* Set up handle. */ data->fd = fd; data->filename = fname; data->encoding = MVM_encoding_type_utf8; result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
static MVMString * take_chars(MVMThreadContext *tc, MVMDecodeStream *ds, MVMint32 chars) { MVMint32 found = 0; MVMString *result = (MVMString *)MVM_repr_alloc_init(tc, tc->instance->VMString); result->body.storage.blob_32 = MVM_malloc(chars * sizeof(MVMGrapheme32)); result->body.storage_type = MVM_STRING_GRAPHEME_32; result->body.num_graphs = chars; while (found < chars) { MVMDecodeStreamChars *cur_chars = ds->chars_head; MVMint32 available = cur_chars->length - ds->chars_head_pos; if (available <= chars - found) { /* We need all that's left in this buffer and likely * more. */ MVMDecodeStreamChars *next_chars = cur_chars->next; memcpy(result->body.storage.blob_32 + found, cur_chars->chars + ds->chars_head_pos, available * sizeof(MVMGrapheme32)); found += available; MVM_free(cur_chars->chars); MVM_free(cur_chars); ds->chars_head = next_chars; ds->chars_head_pos = 0; if (ds->chars_head == NULL) ds->chars_tail = NULL; cur_chars = next_chars; } else { /* There's enough in this buffer to satisfy us, and we'll leave * some behind. */ MVMint32 take = chars - found; memcpy(result->body.storage.blob_32 + found, cur_chars->chars + ds->chars_head_pos, take * sizeof(MVMGrapheme32)); found += take; ds->chars_head_pos += take; } } return result; }
/* Returns the lines (backtrace) of an exception-object as an array. */ MVMObject * MVM_exception_backtrace_strings(MVMThreadContext *tc, MVMObject *ex_obj) { MVMException *ex; MVMFrame *cur_frame; MVMObject *arr; if (IS_CONCRETE(ex_obj) && REPR(ex_obj)->ID == MVM_REPR_ID_MVMException) ex = (MVMException *)ex_obj; else MVM_exception_throw_adhoc(tc, "Op 'backtracestrings' needs an exception object"); cur_frame = ex->body.origin; arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); MVMROOT(tc, arr, { MVMuint32 count = 0; while (cur_frame != NULL) { char *line = MVM_exception_backtrace_line(tc, cur_frame, count++); MVMString *line_str = MVM_string_utf8_decode(tc, tc->instance->VMString, line, strlen(line)); MVMObject *line_obj = MVM_repr_box_str(tc, tc->instance->boot_types.BOOTStr, line_str); MVM_repr_push_o(tc, arr, line_obj); cur_frame = cur_frame->caller; free(line); } });
MVMObject * MVM_radix(MVMThreadContext *tc, MVMint64 radix, MVMString *str, MVMint64 offset, MVMint64 flag) { MVMObject *result; MVMint64 zvalue = 0; MVMint64 zbase = 1; MVMint64 chars = MVM_string_graphs(tc, str); MVMint64 value = zvalue; MVMint64 base = zbase; MVMint64 pos = -1; MVMuint16 neg = 0; MVMint64 ch; if (radix > 36) { MVM_exception_throw_adhoc(tc, "Cannot convert radix of %"PRId64" (max 36)", radix); } ch = (offset < chars) ? MVM_string_get_grapheme_at_nocheck(tc, str, offset) : 0; if ((flag & 0x02) && (ch == '+' || ch == '-')) { neg = (ch == '-'); offset++; ch = (offset < chars) ? MVM_string_get_grapheme_at_nocheck(tc, str, offset) : 0; } while (offset < chars) { if (ch >= '0' && ch <= '9') ch = ch - '0'; /* fast-path for ASCII 0..9 */ else if (ch >= 'a' && ch <= 'z') ch = ch - 'a' + 10; else if (ch >= 'A' && ch <= 'Z') ch = ch - 'A' + 10; else if (ch >= 0xFF21 && ch <= 0xFF3A) ch = ch - 0xFF21 + 10; /* uppercase fullwidth */ else if (ch >= 0xFF41 && ch <= 0xFF5A) ch = ch - 0xFF41 + 10; /* lowercase fullwidth */ else if (ch > 0 && MVM_unicode_codepoint_has_property_value(tc, ch, MVM_UNICODE_PROPERTY_GENERAL_CATEGORY, MVM_unicode_cname_to_property_value_code(tc, MVM_UNICODE_PROPERTY_GENERAL_CATEGORY, STR_WITH_LEN("Nd")))) { /* As of Unicode 6.0.0, we know that Nd category numerals are within * the range 0..9 */ /* the string returned for NUMERIC_VALUE contains a floating point * value, so atoi will stop on the . in the string. This is fine * though, since we'd have to truncate the float regardless. */ ch = atoi(MVM_unicode_codepoint_get_property_cstr(tc, ch, MVM_UNICODE_PROPERTY_NUMERIC_VALUE)); } else break; if (ch >= radix) break; zvalue = zvalue * radix + ch; zbase = zbase * radix; offset++; pos = offset; if (ch != 0 || !(flag & 0x04)) { value=zvalue; base=zbase; } if (offset >= chars) break; ch = MVM_string_get_grapheme_at_nocheck(tc, str, offset); if (ch != '_') continue; offset++; if (offset >= chars) break; ch = MVM_string_get_grapheme_at_nocheck(tc, str, offset); } if (neg || flag & 0x01) { value = -value; } /* initialize the object */ result = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type); MVMROOT(tc, result, { MVMObject *box_type = MVM_hll_current(tc)->int_box_type; MVMROOT(tc, box_type, { MVMObject *boxed = MVM_repr_box_int(tc, box_type, value); MVM_repr_push_o(tc, result, boxed); boxed = MVM_repr_box_int(tc, box_type, base); MVM_repr_push_o(tc, result, boxed); boxed = MVM_repr_box_int(tc, box_type, pos); MVM_repr_push_o(tc, result, boxed); }); });
/* Locates all of the attributes. Puts them onto a flattened, ordered * list of attributes (populating the passed flat_list). Also builds * the index mapping for doing named lookups. Note index is not related * to the storage position. */ static MVMObject * index_mapping_and_flat_list(MVMThreadContext *tc, MVMObject *mro, MVMCPPStructREPRData *repr_data) { MVMInstance *instance = tc->instance; MVMObject *flat_list, *class_list, *attr_map_list; MVMint32 num_classes, i, current_slot = 0; MVMCPPStructNameMap *result; MVMint32 mro_idx = MVM_repr_elems(tc, mro); MVM_gc_root_temp_push(tc, (MVMCollectable **)&mro); flat_list = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type); MVM_gc_root_temp_push(tc, (MVMCollectable **)&flat_list); class_list = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type); MVM_gc_root_temp_push(tc, (MVMCollectable **)&class_list); attr_map_list = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type); MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_map_list); /* Walk through the parents list. */ while (mro_idx) { /* Get current class in MRO. */ MVMObject *type_info = MVM_repr_at_pos_o(tc, mro, --mro_idx); MVMObject *current_class = MVM_repr_at_pos_o(tc, type_info, 0); /* Get its local parents; make sure we're not doing MI. */ MVMObject *parents = MVM_repr_at_pos_o(tc, type_info, 2); MVMint32 num_parents = MVM_repr_elems(tc, parents); if (num_parents <= 1) { /* Get attributes and iterate over them. */ MVMObject *attributes = MVM_repr_at_pos_o(tc, type_info, 1); MVMIter * const attr_iter = (MVMIter *)MVM_iter(tc, attributes); MVMObject *attr_map = NULL; if (MVM_iter_istrue(tc, attr_iter)) { MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_iter); attr_map = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_hash_type); MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_map); } while (MVM_iter_istrue(tc, attr_iter)) { MVMObject *current_slot_obj = MVM_repr_box_int(tc, MVM_hll_current(tc)->int_box_type, current_slot); MVMObject *attr, *name_obj; MVMString *name; MVM_repr_shift_o(tc, (MVMObject *)attr_iter); /* Get attribute. */ attr = MVM_iterval(tc, attr_iter); /* Get its name. */ name_obj = MVM_repr_at_key_o(tc, attr, instance->str_consts.name); name = MVM_repr_get_str(tc, name_obj); MVM_repr_bind_key_o(tc, attr_map, name, current_slot_obj); current_slot++; /* Push attr onto the flat list. */ MVM_repr_push_o(tc, flat_list, attr); } if (attr_map) { MVM_gc_root_temp_pop_n(tc, 2); } /* Add to class list and map list. */ MVM_repr_push_o(tc, class_list, current_class); MVM_repr_push_o(tc, attr_map_list, attr_map); } else { MVM_exception_throw_adhoc(tc, "CPPStruct representation does not support multiple inheritance"); } } MVM_gc_root_temp_pop_n(tc, 4); /* We can now form the name map. */ num_classes = MVM_repr_elems(tc, class_list); result = (MVMCPPStructNameMap *) MVM_malloc(sizeof(MVMCPPStructNameMap) * (1 + num_classes)); for (i = 0; i < num_classes; i++) { result[i].class_key = MVM_repr_at_pos_o(tc, class_list, i); result[i].name_map = MVM_repr_at_pos_o(tc, attr_map_list, i); } /* set the end to be NULL, it's useful for iteration. */ result[i].class_key = NULL; repr_data->name_to_index_mapping = result; return flat_list; }
/* Decodes all the buffers, producing a string containing all the decoded * characters. */ MVMString * MVM_string_decodestream_get_all(MVMThreadContext *tc, MVMDecodeStream *ds) { MVMString *result = (MVMString *)MVM_repr_alloc_init(tc, tc->instance->VMString); result->body.storage_type = MVM_STRING_GRAPHEME_32; /* Decode anything remaining and flush normalization buffer. */ reached_eof(tc, ds); /* If there's no codepoint buffer, then return the empty string. */ if (!ds->chars_head) { result->body.storage.blob_32 = NULL; result->body.num_graphs = 0; } /* If there's exactly one resulting codepoint buffer and we swallowed none * of it, just use it. */ else if (ds->chars_head == ds->chars_tail && ds->chars_head_pos == 0) { /* Set up result string. */ result->body.storage.blob_32 = ds->chars_head->chars; result->body.num_graphs = ds->chars_head->length; /* Don't free the buffer's memory itself, just the holder, as we * stole that for the buffer into the string above. */ MVM_free(ds->chars_head); ds->chars_head = ds->chars_tail = NULL; } /* Otherwise, need to assemble all the things. */ else { /* Calculate length. */ MVMint32 length = 0, pos = 0; MVMDecodeStreamChars *cur_chars = ds->chars_head; while (cur_chars) { if (cur_chars == ds->chars_head) length += cur_chars->length - ds->chars_head_pos; else length += cur_chars->length; cur_chars = cur_chars->next; } /* Allocate a result buffer of the right size. */ result->body.storage.blob_32 = MVM_malloc(length * sizeof(MVMGrapheme32)); result->body.num_graphs = length; /* Copy all the things into the target, freeing as we go. */ cur_chars = ds->chars_head; while (cur_chars) { if (cur_chars == ds->chars_head) { MVMint32 to_copy = ds->chars_head->length - ds->chars_head_pos; memcpy(result->body.storage.blob_32 + pos, cur_chars->chars + ds->chars_head_pos, cur_chars->length * sizeof(MVMGrapheme32)); pos += to_copy; } else { memcpy(result->body.storage.blob_32 + pos, cur_chars->chars, cur_chars->length * sizeof(MVMGrapheme32)); pos += cur_chars->length; } cur_chars = cur_chars->next; } ds->chars_head = ds->chars_tail = NULL; } return result; }
/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename); uv_fs_t req; uv_file fd; int flag; /* Resolve mode description to flags. */ { char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); if (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fname, fmode, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode for file %s: %s", fname, fmode); } MVM_free(fmode); } /* Try to open the file. */ if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) { char *waste[] = { fname, NULL }; const char *err = uv_strerror(req.result); uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err); } uv_fs_req_cleanup(&req); /* Check that we didn't open a directory by accident. If fstat fails, just move on: Most of the documented error cases should already have triggered when opening the file, and we can't do anything about the others; a failure also does not necessarily imply that the file descriptor cannot be used for reading/writing. */ if (uv_fs_fstat(tc->loop, &req, fd, NULL) == 0 && (req.statbuf.st_mode & S_IFMT) == S_IFDIR) { char *waste[] = { fname, NULL }; uv_fs_req_cleanup(&req); if (uv_fs_close(tc->loop, &req, fd, NULL) < 0) { const char *err = uv_strerror(req.result); uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s, which we failed to close: %s", fname, err); } uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname); } uv_fs_req_cleanup(&req); /* Set up handle. */ { MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); data->fd = fd; data->filename = fname; data->encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } }
static MVMObject * new_hash(MVMThreadContext *tc) { return MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_hash_type); }
/* Creates a new thread handle with the MVMThread representation. Does not * actually start execution of the thread. */ MVMObject * MVM_thread_new(MVMThreadContext *tc, MVMObject *invokee, MVMint64 app_lifetime) { MVMThread *thread; MVMROOT(tc, invokee, { thread = (MVMThread *)MVM_repr_alloc_init(tc, tc->instance->Thread); });
/* Open a filehandle, returning a handle. */ MVMObject * MVM_dir_open(MVMThreadContext *tc, MVMString *dirname) { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIODirIter * const data = calloc(1, sizeof(MVMIODirIter)); #ifdef _WIN32 char *name; int str_len; wchar_t *wname; wchar_t *dir_name; name = MVM_string_utf8_encode_C_string(tc, dirname); wname = UTF8ToUnicode(name); MVM_free(name); str_len = wcslen(wname); if (str_len > MAX_PATH - 2) { // the length of later appended '\*' is 2 wchar_t abs_dirname[4096]; /* 4096 should be enough for absolute path */ wchar_t *lpp_part; /* You cannot use the "\\?\" prefix with a relative path, * relative paths are always limited to a total of MAX_PATH characters. * see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx */ if (!GetFullPathNameW(wname, 4096, abs_dirname, &lpp_part)) { MVM_free(wname); MVM_exception_throw_adhoc(tc, "Directory path is wrong: %d", GetLastError()); } MVM_free(wname); str_len = wcslen(abs_dirname); dir_name = (wchar_t *)MVM_malloc((str_len + 7) * sizeof(wchar_t)); wcscpy(dir_name, L"\\\\?\\"); wcscat(dir_name, abs_dirname); } else { dir_name = (wchar_t *)MVM_malloc((str_len + 3) * sizeof(wchar_t)); wcscpy(dir_name, wname); MVM_free(wname); } wcscat(dir_name, L"\\*"); /* Three characters are for the "\*" plus NULL appended. * see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200%28v=vs.85%29.aspx */ data->dir_name = dir_name; data->dir_handle = INVALID_HANDLE_VALUE; #else char * const dir_name = MVM_string_utf8_encode_C_string(tc, dirname); DIR * const dir_handle = opendir(dir_name); MVM_free(dir_name); if (!dir_handle) MVM_exception_throw_adhoc(tc, "Failed to open dir: %d", errno); data->dir_handle = dir_handle; #endif data->encoding = MVM_encoding_type_utf8; result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
MVMInstance * MVM_vm_create_instance(void) { MVMInstance *instance; int init_stat; /* Set up instance data structure. */ instance = calloc(1, sizeof(MVMInstance)); /* Create the main thread's ThreadContext and stash it. */ instance->main_thread = MVM_tc_create(instance); /* No user threads when we start, and next thread to be created gets ID 1 * (the main thread got ID 0). */ instance->num_user_threads = 0; MVM_store(&instance->next_user_thread_id, 1); /* Set up the permanent roots storage. */ instance->num_permroots = 0; instance->alloc_permroots = 16; instance->permroots = malloc(sizeof(MVMCollectable **) * instance->alloc_permroots); init_mutex(instance->mutex_permroots, "permanent roots"); /* Set up REPR registry mutex. */ init_mutex(instance->mutex_repr_registry, "REPR registry"); /* Set up HLL config mutex. */ init_mutex(instance->mutex_hllconfigs, "hll configs"); /* Set up weak reference hash mutex. */ init_mutex(instance->mutex_sc_weakhash, "sc weakhash"); /* Set up loaded compunits hash mutex. */ init_mutex(instance->mutex_loaded_compunits, "loaded compunits"); /* Set up container registry mutex. */ init_mutex(instance->mutex_container_registry, "container registry"); /* Bootstrap 6model. It is assumed the GC will not be called during this. */ MVM_6model_bootstrap(instance->main_thread); /* Fix up main thread's usecapture. */ instance->main_thread->cur_usecapture = MVM_repr_alloc_init(instance->main_thread, instance->CallCapture); /* get libuv default event loop. */ instance->default_loop = instance->main_thread->loop; /* Create main thread object, and also make it the start of the all threads * linked list. */ MVM_store(&instance->threads, (instance->main_thread->thread_obj = (MVMThread *) REPR(instance->boot_types.BOOTThread)->allocate( instance->main_thread, STABLE(instance->boot_types.BOOTThread)))); instance->threads->body.stage = MVM_thread_stage_started; instance->threads->body.tc = instance->main_thread; /* Create compiler registry */ instance->compiler_registry = MVM_repr_alloc_init(instance->main_thread, instance->boot_types.BOOTHash); /* Set up compiler registr mutex. */ init_mutex(instance->mutex_compiler_registry, "compiler registry"); /* Create hll symbol tables */ instance->hll_syms = MVM_repr_alloc_init(instance->main_thread, instance->boot_types.BOOTHash); /* Set up hll symbol tables mutex. */ init_mutex(instance->mutex_hll_syms, "hll syms"); /* Initialize string cclass handling. */ MVM_string_cclass_init(instance->main_thread); /* Set up some string constants commonly used. */ string_consts(instance->main_thread); return instance; }