/* Takes a string and sets it up as a decode stream separator. */ void MVM_string_decode_stream_sep_from_strings(MVMThreadContext *tc, MVMDecodeStreamSeparators *sep_spec, MVMString **seps, MVMint32 num_seps) { MVMGraphemeIter gi; MVMint32 i, graph_length, graph_pos; if (num_seps > 0xFFF) MVM_exception_throw_adhoc(tc, "Too many line separators"); MVM_free(sep_spec->sep_lengths); MVM_free(sep_spec->sep_graphemes); MVM_free(sep_spec->final_graphemes); sep_spec->num_seps = num_seps; sep_spec->sep_lengths = MVM_malloc(num_seps * sizeof(MVMint32)); graph_length = 0; for (i = 0; i < num_seps; i++) { MVMuint32 num_graphs = MVM_string_graphs(tc, seps[i]); if (num_graphs > 0xFFFF) MVM_exception_throw_adhoc(tc, "Line separator too long"); sep_spec->sep_lengths[i] = num_graphs; graph_length += num_graphs; } sep_spec->sep_graphemes = MVM_malloc(graph_length * sizeof(MVMGrapheme32)); graph_pos = 0; for (i = 0; i < num_seps; i++) { MVM_string_gi_init(tc, &gi, seps[i]); while (MVM_string_gi_has_more(tc, &gi)) sep_spec->sep_graphemes[graph_pos++] = MVM_string_gi_get_grapheme(tc, &gi); } cache_sep_info(tc, sep_spec); }
/* Throws away byte buffers no longer needed. */ void MVM_string_decodestream_discard_to(MVMThreadContext *tc, MVMDecodeStream *ds, const MVMDecodeStreamBytes *bytes, MVMint32 pos) { while (ds->bytes_head != bytes) { MVMDecodeStreamBytes *discard = ds->bytes_head; ds->abs_byte_pos += discard->length - ds->bytes_head_pos; ds->bytes_head = discard->next; ds->bytes_head_pos = 0; MVM_free(discard->bytes); MVM_free(discard); } if (!ds->bytes_head && pos == 0) return; if (ds->bytes_head->length == pos) { /* We ate all of the new head buffer too; also free it. */ MVMDecodeStreamBytes *discard = ds->bytes_head; ds->abs_byte_pos += discard->length - ds->bytes_head_pos; ds->bytes_head = discard->next; ds->bytes_head_pos = 0; MVM_free(discard->bytes); MVM_free(discard); if (ds->bytes_head == NULL) ds->bytes_tail = NULL; } else { ds->abs_byte_pos += pos - ds->bytes_head_pos; ds->bytes_head_pos = pos; } }
/* Writes the specified string to the file handle, maybe with a newline. */ static MVMint64 write_str(MVMThreadContext *tc, MVMOSHandle *h, MVMString *str, MVMint64 newline) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; MVMuint64 output_size; MVMint64 bytes_written; char *output = MVM_string_encode(tc, str, 0, -1, &output_size, data->encoding, NULL, MVM_TRANSLATE_NEWLINE_OUTPUT); uv_buf_t write_buf = uv_buf_init(output, output_size); uv_fs_t req; bytes_written = uv_fs_write(tc->loop, &req, data->fd, &write_buf, 1, -1, NULL); if (bytes_written < 0) { MVM_free(output); MVM_exception_throw_adhoc(tc, "Failed to write bytes to filehandle: %s", uv_strerror(req.result)); } MVM_free(output); if (newline) { uv_buf_t nl = uv_buf_init("\n", 1); if (uv_fs_write(tc->loop, &req, data->fd, &nl, 1, -1, NULL) < 0) MVM_exception_throw_adhoc(tc, "Failed to write newline to filehandle: %s", uv_strerror(req.result)); bytes_written++; } return bytes_written; }
/* Copies up to the requested number of bytes into the supplied buffer, and * returns the number of bytes we actually copied. Takes from from the start * of the stream. */ MVMint64 MVM_string_decodestream_bytes_to_buf(MVMThreadContext *tc, MVMDecodeStream *ds, char **buf, MVMint32 bytes) { MVMint32 taken = 0; *buf = NULL; while (taken < bytes && ds->bytes_head) { /* Take what we can. */ MVMDecodeStreamBytes *cur_bytes = ds->bytes_head; MVMint32 required = bytes - taken; MVMint32 available = cur_bytes->length - ds->bytes_head_pos; if (available <= required) { /* Take everything in this buffer and remove it. */ if (!*buf) *buf = MVM_malloc(cur_bytes->next ? bytes : available); memcpy(*buf + taken, cur_bytes->bytes + ds->bytes_head_pos, available); taken += available; ds->bytes_head = cur_bytes->next; ds->bytes_head_pos = 0; MVM_free(cur_bytes->bytes); MVM_free(cur_bytes); } else { /* Just take what we need. */ if (!*buf) *buf = MVM_malloc(required); memcpy(*buf + taken, cur_bytes->bytes + ds->bytes_head_pos, required); taken += required; ds->bytes_head_pos += required; } } if (ds->bytes_head == NULL) ds->bytes_tail = NULL; ds->abs_byte_pos += taken; return taken; }
/* 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); 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 (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fmode, NULL }; MVM_free(fname); MVM_exception_throw_adhoc_free(tc, waste, "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) { char *waste[] = { fname, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "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; MVM_string_decode_stream_sep_default(tc, &(data->sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
/* Adds a static frame table index reference to the collectable snapshot entry, * either using an existing table entry or adding a new one. */ static void set_static_frame_index(MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMHeapSnapshotCollectable *col, MVMStaticFrame *sf) { MVMuint64 name_idx = get_vm_string_index(tc, ss, sf->body.name); MVMuint64 cuid_idx = get_vm_string_index(tc, ss, sf->body.cuuid); MVMCompUnit *cu = sf->body.cu; MVMBytecodeAnnotation *ann = MVM_bytecode_resolve_annotation(tc, &(sf->body), 0); MVMuint64 line = ann ? ann->line_number : 1; MVMuint64 file_idx = ann && ann->filename_string_heap_index < cu->body.num_strings ? get_vm_string_index(tc, ss, MVM_cu_string(tc, cu, ann->filename_string_heap_index)) : get_vm_string_index(tc, ss, cu->body.filename); MVMuint64 i; MVMHeapSnapshotStaticFrame *s; for (i = 0; i < ss->col->num_static_frames; i++) { s = &(ss->col->static_frames[i]); if (s->name == name_idx && s->cuid == cuid_idx && s->line == line && s->file == file_idx) { col->type_or_frame_index = i; MVM_free(ann); return; } } MVM_free(ann); grow_storage(&(ss->col->static_frames), &(ss->col->num_static_frames), &(ss->col->alloc_static_frames), sizeof(MVMHeapSnapshotStaticFrame)); s = &(ss->col->static_frames[ss->col->num_static_frames]); s->name = name_idx; s->cuid = cuid_idx; s->line = line; s->file = file_idx; col->type_or_frame_index = ss->col->num_static_frames; ss->col->num_static_frames++; }
/* Cleans up reader state. */ static void cleanup_all(MVMThreadContext *tc, ReaderState *rs) { if (rs->frame_outer_fixups) { MVM_free(rs->frame_outer_fixups); rs->frame_outer_fixups = NULL; } MVM_free(rs); }
MVMint64 MVM_io_syncstream_write_str(MVMThreadContext *tc, MVMOSHandle *h, MVMString *str, MVMint64 newline) { MVMIOSyncStreamData *data = (MVMIOSyncStreamData *)h->body.data; char *output; MVMuint64 output_size; uv_write_t *req; uv_buf_t write_buf; int r; output = MVM_string_encode(tc, str, 0, -1, &output_size, data->encoding); if (newline) { output = (char *)MVM_realloc(output, ++output_size); output[output_size - 1] = '\n'; } req = MVM_malloc(sizeof(uv_write_t)); write_buf = uv_buf_init(output, output_size); uv_ref((uv_handle_t *)data->handle); if ((r = uv_write(req, data->handle, &write_buf, 1, write_cb)) < 0) { uv_unref((uv_handle_t *)data->handle); MVM_free(req); MVM_free(output); MVM_exception_throw_adhoc(tc, "Failed to write string to stream: %s", uv_strerror(r)); } else { uv_run(tc->loop, UV_RUN_DEFAULT); MVM_free(output); } data->total_bytes_written += output_size; return output_size; }
/* Establishes a connection. */ static void socket_connect(MVMThreadContext *tc, MVMOSHandle *h, MVMString *host, MVMint64 port) { MVMIOSyncSocketData *data = (MVMIOSyncSocketData *)h->body.data; unsigned int interval_id; interval_id = MVM_telemetry_interval_start(tc, "syncsocket connect"); if (!data->handle) { struct sockaddr *dest = MVM_io_resolve_host_name(tc, host, port); int r; Socket s = socket(dest->sa_family , SOCK_STREAM , 0); if (MVM_IS_SOCKET_ERROR(s)) { MVM_free(dest); MVM_telemetry_interval_stop(tc, interval_id, "syncsocket connect"); throw_error(tc, s, "create socket"); } do { MVM_gc_mark_thread_blocked(tc); r = connect(s, dest, (socklen_t)get_struct_size_for_family(dest->sa_family)); MVM_gc_mark_thread_unblocked(tc); } while(r == -1 && errno == EINTR); MVM_free(dest); if (MVM_IS_SOCKET_ERROR(r)) { MVM_telemetry_interval_stop(tc, interval_id, "syncsocket connect"); throw_error(tc, s, "connect socket"); } data->handle = s; } else { MVM_telemetry_interval_stop(tc, interval_id, "syncsocket didn't connect"); MVM_exception_throw_adhoc(tc, "Socket is already bound or connected"); } }
static char * jitcode_name(MVMThreadContext *tc, MVMJitCode *code) { MVMuint64 cuuid_len; MVMuint64 name_len; MVMuint8 *cuuid = MVM_string_ascii_encode(tc, code->sf->body.cuuid, &cuuid_len); MVMuint8 *name = MVM_string_ascii_encode(tc, code->sf->body.name, &name_len); MVMuint64 dirname_len = strlen(tc->instance->jit_bytecode_dir); // 4 chars for prefix, 3 chars for the separators, 4 for the postfix, 1 for the 0 char *filename = MVM_malloc(dirname_len + name_len + cuuid_len + 12); char *dst = filename; memcpy(dst, tc->instance->jit_bytecode_dir, dirname_len); dst[dirname_len] = '/'; dst += dirname_len + 1; memcpy(dst, "jit-", 4); dst += 4; memcpy(dst, cuuid, cuuid_len); dst[cuuid_len] = '.'; dst += cuuid_len + 1; memcpy(dst, name, name_len); dst += name_len; memcpy(dst, ".bin", 5); MVM_free(name); MVM_free(cuuid); return filename; }
/* Dumps the statistics associated with a particular callsite object. */ void dump_stats_by_callsite(MVMThreadContext *tc, DumpStr *ds, MVMSpeshStatsByCallsite *css) { MVMuint32 i, j, k; if (css->cs) dump_callsite(tc, ds, css->cs); else append(ds, "No interned callsite\n"); appendf(ds, " Callsite hits: %d\n\n", css->hits); if (css->osr_hits) appendf(ds, " OSR hits: %d\n\n", css->osr_hits); appendf(ds, " Maximum stack depth: %d\n\n", css->max_depth); for (i = 0; i < css->num_by_type; i++) { MVMSpeshStatsByType *tss = &(css->by_type[i]); appendf(ds, " Type tuple %d\n", i); dump_stats_type_tuple(tc, ds, css->cs, tss->arg_types, " "); appendf(ds, " Hits: %d\n", tss->hits); if (tss->osr_hits) appendf(ds, " OSR hits: %d\n", tss->osr_hits); appendf(ds, " Maximum stack depth: %d\n", tss->max_depth); if (tss->num_by_offset) { append(ds, " Logged at offset:\n"); for (j = 0; j < tss->num_by_offset; j++) { MVMSpeshStatsByOffset *oss = &(tss->by_offset[j]); appendf(ds, " %d:\n", oss->bytecode_offset); for (k = 0; k < oss->num_types; k++) appendf(ds, " %d x type %s (%s)\n", oss->types[k].count, MVM_6model_get_stable_debug_name(tc, oss->types[k].type->st), (oss->types[k].type_concrete ? "Conc" : "TypeObj")); for (k = 0; k < oss->num_invokes; k++) { char *body_name = MVM_string_utf8_encode_C_string(tc, oss->invokes[k].sf->body.name); char *body_cuuid = MVM_string_utf8_encode_C_string(tc, oss->invokes[k].sf->body.cuuid); appendf(ds, " %d x static frame '%s' (%s) (caller is outer: %d, multi %d)\n", oss->invokes[k].count, body_name, body_cuuid, oss->invokes[k].caller_is_outer_count, oss->invokes[k].was_multi_count); MVM_free(body_name); MVM_free(body_cuuid); } for (k = 0; k < oss->num_type_tuples; k++) { appendf(ds, " %d x type tuple:\n", oss->type_tuples[k].count); dump_stats_type_tuple(tc, ds, oss->type_tuples[k].cs, oss->type_tuples[k].arg_types, " "); } for (k = 0; k < oss->num_plugin_guards; k++) appendf(ds, " %d x spesh plugin guard index %d\n", oss->plugin_guards[k].count, oss->plugin_guards[k].guard_index); } } append(ds, "\n"); } }
/* This function may return any type of sockaddr e.g. sockaddr_un, sockaddr_in or sockaddr_in6 * It shouldn't be a problem with general code as long as the port number is kept below the int16 limit: 65536 * After this it defines the family which may spawn non internet sockaddr's * The family can be extracted by (port >> 16) & USHORT_MAX * * Currently supported families: * * AF_UNSPEC = 1 * Unspecified, in most cases should be equal to AF_INET or AF_INET6 * * AF_UNIX = 1 * Unix domain socket, will spawn a sockaddr_un which will use the given host as path * e.g: MVM_io_resolve_host_name(tc, "/run/moarvm.sock", 1 << 16) * will spawn an unix domain socket on /run/moarvm.sock * * AF_INET = 2 * IPv4 socket * * AF_INET6 = 10 * IPv6 socket */ struct sockaddr * MVM_io_resolve_host_name(MVMThreadContext *tc, MVMString *host, MVMint64 port) { char *host_cstr = MVM_string_utf8_encode_C_string(tc, host); struct sockaddr *dest; int error; struct addrinfo *result; char port_cstr[8]; unsigned short family = (port >> 16) & USHRT_MAX; struct addrinfo hints; #ifndef _WIN32 /* AF_UNIX = 1 */ if (family == AF_UNIX) { struct sockaddr_un *result_un = MVM_malloc(sizeof(struct sockaddr_un)); if (strlen(host_cstr) > 107) { MVM_free(result_un); MVM_free(host_cstr); MVM_exception_throw_adhoc(tc, "Socket path can only be maximal 107 characters long"); } result_un->sun_family = AF_UNIX; strcpy(result_un->sun_path, host_cstr); MVM_free(host_cstr); return (struct sockaddr *)result_un; } #endif hints.ai_family = family; hints.ai_socktype = 0; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_addr = NULL; hints.ai_canonname = NULL; hints.ai_next = NULL; snprintf(port_cstr, 8, "%d", (int)port); MVM_gc_mark_thread_blocked(tc); error = getaddrinfo(host_cstr, port_cstr, &hints, &result); MVM_gc_mark_thread_unblocked(tc); if (error == 0) { size_t size = get_struct_size_for_family(result->ai_addr->sa_family); MVM_free(host_cstr); dest = MVM_malloc(size); memcpy(dest, result->ai_addr, size); } else { char *waste[] = { host_cstr, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Failed to resolve host name '%s' with family %d. Error: '%s'", host_cstr, family, gai_strerror(error)); } freeaddrinfo(result); return dest; }
/* 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(MVMThreadContext *parent, MVMInstance *instance) { MVMThreadContext *tc = MVM_calloc(1, sizeof(MVMThreadContext)); /* Associate with VM instance. */ tc->instance = instance; /* Use default loop for main thread; create a new one for others. */ if (instance->main_thread) { int r; tc->loop = MVM_calloc(1, sizeof(uv_loop_t)); r = uv_loop_init(tc->loop); if (r < 0) { MVM_free(tc->loop); MVM_free(tc); MVM_exception_throw_adhoc(parent, "Could not create a new Thread: %s", uv_strerror(r)); } } else { tc->loop = uv_default_loop(); } /* Set up GC nursery. We only allocate tospace initially, and allocate * fromspace the first time this thread GCs, provided it ever does. */ tc->nursery_tospace = MVM_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 = MVM_TEMP_ROOT_BASE_ALLOC; tc->temproots = MVM_malloc(sizeof(MVMCollectable **) * tc->alloc_temproots); /* Set up intergenerational root handling. */ tc->num_gen2roots = 0; tc->alloc_gen2roots = 64; tc->gen2roots = MVM_malloc(sizeof(MVMCollectable *) * tc->alloc_gen2roots); /* Set up the second generation allocator. */ tc->gen2 = MVM_gc_gen2_create(instance); /* Allocate an initial call stack region for the thread. */ MVM_callstack_region_init(tc); /* Initialize random number generator state. */ MVM_proc_seed(tc, (MVM_platform_now() / 10000) * MVM_proc_getpid(tc)); /* Initialize frame sequence numbers */ tc->next_frame_nr = 0; tc->current_frame_nr = 0; /* Initialize last_payload, so we can be sure it's never NULL and don't * need to check. */ tc->last_payload = instance->VMNull; return tc; }
static MVMString * take_chars(MVMThreadContext *tc, MVMDecodeStream *ds, MVMint32 chars, MVMint32 exclude) { MVMString *result; MVMint32 found = 0; MVMint32 result_found = 0; MVMint32 result_chars = chars - exclude; if (result_chars < 0) MVM_exception_throw_adhoc(tc, "DecodeStream take_chars: chars - exclude < 0 should never happen"); result = (MVMString *)MVM_repr_alloc_init(tc, tc->instance->VMString); result->body.storage.blob_32 = MVM_malloc(result_chars * sizeof(MVMGrapheme32)); result->body.storage_type = MVM_STRING_GRAPHEME_32; result->body.num_graphs = result_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; if (available <= result_chars - result_found) { memcpy(result->body.storage.blob_32 + result_found, cur_chars->chars + ds->chars_head_pos, available * sizeof(MVMGrapheme32)); result_found += available; } else { MVMint32 to_copy = result_chars - result_found; memcpy(result->body.storage.blob_32 + result_found, cur_chars->chars + ds->chars_head_pos, to_copy * sizeof(MVMGrapheme32)); result_found += to_copy; } 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; } else { /* There's enough in this buffer to satisfy us, and we'll leave * some behind. */ MVMint32 take = chars - found; MVMint32 to_copy = result_chars - result_found; memcpy(result->body.storage.blob_32 + result_found, cur_chars->chars + ds->chars_head_pos, to_copy * sizeof(MVMGrapheme32)); result_found += to_copy; found += take; ds->chars_head_pos += take; } } return result; }
/* Change directory. */ void MVM_dir_chdir(MVMThreadContext *tc, MVMString *dir) { char * const dirstring = MVM_string_utf8_encode_C_string(tc, dir); if (uv_chdir((const char *)dirstring) != 0) { MVM_free(dirstring); MVM_exception_throw_adhoc(tc, "chdir failed: %s", uv_strerror(errno)); } MVM_free(dirstring); }
/* Frees data associated with the handle. */ static void gc_free(MVMThreadContext *tc, MVMObject *h, void *d) { MVMIOFileData *data = (MVMIOFileData *)d; if (data) { if (data->ds) MVM_string_decodestream_destory(tc, data->ds); if (data->filename) MVM_free(data->filename); MVM_free(data); } }
/* Destroys a decoding stream, freeing all associated memory (including the * buffers). */ void MVM_string_decodestream_destory(MVMThreadContext *tc, MVMDecodeStream *ds) { MVMDecodeStreamBytes *cur_bytes = ds->bytes_head; while (cur_bytes) { MVMDecodeStreamBytes *next_bytes = cur_bytes->next; MVM_free(cur_bytes->bytes); MVM_free(cur_bytes); cur_bytes = next_bytes; } MVM_free(ds); }
/* Tries to intern the callsite, freeing and updating the one passed in and * replacing it with an already interned one if we find it. */ MVM_PUBLIC void MVM_callsite_try_intern(MVMThreadContext *tc, MVMCallsite **cs_ptr) { MVMCallsiteInterns *interns = tc->instance->callsite_interns; MVMCallsite *cs = *cs_ptr; MVMint32 num_flags = cs->flag_count; MVMint32 num_nameds = MVM_callsite_num_nameds(tc, cs); MVMint32 i, found; /* Can't intern anything with flattening. */ if (cs->has_flattening) return; /* Also can't intern past the max arity. */ if (num_flags >= MVM_INTERN_ARITY_LIMIT) return; /* Can intern things with nameds, provided we know the names. */ if (num_nameds > 0 && !cs->arg_names) return; /* Obtain mutex protecting interns store. */ uv_mutex_lock(&tc->instance->mutex_callsite_interns); /* Search for a match. */ found = 0; for (i = 0; i < interns->num_by_arity[num_flags]; i++) { if (callsites_equal(tc, interns->by_arity[num_flags][i], cs, num_flags, num_nameds)) { /* Got a match! Free the one we were passed and replace it with * the interned one. */ if (num_flags) MVM_free(cs->arg_flags); MVM_free(cs->arg_names); MVM_free(cs); *cs_ptr = interns->by_arity[num_flags][i]; found = 1; break; } } /* If it wasn't found, store it for the future. */ if (!found) { if (interns->num_by_arity[num_flags] % 8 == 0) { if (interns->num_by_arity[num_flags]) interns->by_arity[num_flags] = MVM_realloc( interns->by_arity[num_flags], sizeof(MVMCallsite *) * (interns->num_by_arity[num_flags] + 8)); else interns->by_arity[num_flags] = MVM_malloc(sizeof(MVMCallsite *) * 8); } interns->by_arity[num_flags][interns->num_by_arity[num_flags]++] = cs; cs->is_interned = 1; } /* Finally, release mutex. */ uv_mutex_unlock(&tc->instance->mutex_callsite_interns); }
/* Destroys a decoding stream, freeing all associated memory (including the * buffers). */ void MVM_string_decodestream_destory(MVMThreadContext *tc, MVMDecodeStream *ds) { MVMDecodeStreamBytes *cur_bytes = ds->bytes_head; while (cur_bytes) { MVMDecodeStreamBytes *next_bytes = cur_bytes->next; MVM_free(cur_bytes->bytes); MVM_free(cur_bytes); cur_bytes = next_bytes; } MVM_unicode_normalizer_cleanup(tc, &(ds->norm)); MVM_free(ds); }
void MVM_region_destroy(MVMThreadContext *tc, MVMRegionAlloc *alloc) { MVMRegionBlock *block = alloc->block; /* Free all of the allocated memory. */ while (block) { MVMRegionBlock *prev = block->prev; MVM_free(block->buffer); MVM_free(block); block = prev; } alloc->block = NULL; }
void MVM_file_chmod(MVMThreadContext *tc, MVMString *f, MVMint64 flag) { char * const a = MVM_string_utf8_encode_C_string(tc, f); uv_fs_t req; if(uv_fs_chmod(tc->loop, &req, a, flag, NULL) < 0 ) { MVM_free(a); MVM_exception_throw_adhoc(tc, "Failed to set permissions on path: %s", uv_strerror(req.result)); } MVM_free(a); }
/* Remove a directory recursively. */ void MVM_dir_rmdir(MVMThreadContext *tc, MVMString *path) { char * const pathname = MVM_string_utf8_encode_C_string(tc, path); uv_fs_t req; if(uv_fs_rmdir(tc->loop, &req, pathname, NULL) < 0 ) { MVM_free(pathname); MVM_exception_throw_adhoc(tc, "Failed to rmdir: %s", uv_strerror(req.result)); } MVM_free(pathname); }
/* Clean up an arguments processing context. */ void MVM_args_proc_cleanup(MVMThreadContext *tc, MVMArgProcContext *ctx) { if (ctx->arg_flags) { MVM_free(ctx->arg_flags); MVM_free(ctx->args); } if (ctx->named_used_size > 64) { MVM_fixed_size_free(tc, tc->instance->fsa, ctx->named_used_size, ctx->named_used.byte_array); ctx->named_used_size = 0; } }
/* 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); int fd; int flag; STAT statbuf; /* 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. */ #ifdef _WIN32 flag |= _O_BINARY; #endif if ((fd = open((const char *)fname, flag, DEFAULT_MODE)) == -1) { char *waste[] = { fname, NULL }; const char *err = strerror(errno); MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err); } /* 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 (fstat(fd, &statbuf) == 0 && (statbuf.st_mode & S_IFMT) == S_IFDIR) { char *waste[] = { fname, NULL }; if (close(fd) == -1) { const char *err = strerror(errno); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s, which we failed to close: %s", fname, err); } MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname); } /* Set up handle. */ MVM_free(fname); { 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->seekable = MVM_platform_lseek(fd, 0, SEEK_CUR) != -1; result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } }
static void late_bound_find_method_return(MVMThreadContext *tc, void *sr_data) { FindMethodSRData *fm = (FindMethodSRData *)sr_data; if (MVM_is_null(tc, fm->res->o) || !IS_CONCRETE(fm->res->o)) { MVMObject *obj = fm->obj; MVMString *name = fm->name; MVM_free(fm); die_over_missing_method(tc, obj, name); } else { MVM_free(fm); } }
/* rename one file to another. */ void MVM_file_rename(MVMThreadContext *tc, MVMString *src, MVMString *dest) { char * const a = MVM_string_utf8_encode_C_string(tc, src); char * const b = MVM_string_utf8_encode_C_string(tc, dest); uv_fs_t req; if(uv_fs_rename(tc->loop, &req, a, b, NULL) < 0 ) { MVM_free(a); MVM_free(b); MVM_exception_throw_adhoc(tc, "Failed to rename file: %s", uv_strerror(req.result)); } MVM_free(a); MVM_free(b); }
static uv_stat_t file_info(MVMThreadContext *tc, MVMString *filename, MVMint32 use_lstat) { char * const a = MVM_string_utf8_encode_C_string(tc, filename); uv_fs_t req; if ((use_lstat ? uv_fs_lstat(tc->loop, &req, a, NULL) : uv_fs_stat(tc->loop, &req, a, NULL) ) < 0) { MVM_free(a); MVM_exception_throw_adhoc(tc, "Failed to stat file: %s", uv_strerror(req.result)); } MVM_free(a); return req.statbuf; }
void MVM_callsite_destroy(MVMCallsite *cs) { if (cs->flag_count) { MVM_free(cs->arg_flags); } if (cs->arg_names) { MVM_free(cs->arg_names); } if (cs->with_invocant) { MVM_callsite_destroy(cs->with_invocant); } MVM_free(cs); }
/* Frees data associated with the directory handle. */ static void gc_free(MVMThreadContext *tc, MVMObject *h, void *d) { MVMIODirIter *data = (MVMIODirIter *)d; if (data) { #ifdef _WIN32 if (data->dir_name) MVM_free(data->dir_name); if (data->dir_handle) FindClose(data->dir_handle); #else if (data->dir_handle) closedir(data->dir_handle); #endif MVM_free(data); } }
/* Actually, it may return sockaddr_in6 as well; it's not a problem for us, because we just * pass is straight to uv, and the first thing it does is it looks at the address family, * but it's a thing to remember if someone feels like peeking inside the returned struct. */ struct sockaddr * MVM_io_resolve_host_name(MVMThreadContext *tc, MVMString *host, MVMint64 port) { char *host_cstr = MVM_string_utf8_encode_C_string(tc, host); struct sockaddr *dest; struct addrinfo *result; int error; char port_cstr[8]; snprintf(port_cstr, 8, "%d", (int)port); error = getaddrinfo(host_cstr, port_cstr, NULL, &result); MVM_free(host_cstr); if (error == 0) { if (result->ai_addr->sa_family == AF_INET6) { dest = MVM_malloc(sizeof(struct sockaddr_in6)); memcpy(dest, result->ai_addr, sizeof(struct sockaddr_in6)); } else { dest = MVM_malloc(sizeof(struct sockaddr)); memcpy(dest, result->ai_addr, sizeof(struct sockaddr)); } } else { MVM_exception_throw_adhoc(tc, "Failed to resolve host name"); } freeaddrinfo(result); return dest; }