MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env) { MVMint64 result = 0, spawn_result = 0; uv_process_t *process = calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; { MVMint64 len = strlen(cmdin); MVMint64 i; for (i = 0; i < len; i++) if (cmdin[i] == '/') cmdin[i] = '\\'; } args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif INIT_ENV(); SPAWN(_cmd); FREE_ENV(); free(_cwd); #ifdef _WIN32 free(_cmd); #endif free(cmdin); return result; }
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMObject *argv, MVMString *cwd, MVMObject *env) { MVMint64 result = 0, spawn_result = 0; uv_process_t *process = calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); const MVMuint64 arg_size = MVM_repr_elems(tc, argv); char **args = malloc((arg_size + 1) * sizeof(char *)); MVMRegister reg; i = 0; while(i < arg_size) { REPR(argv)->pos_funcs.at_pos(tc, STABLE(argv), argv, OBJECT_BODY(argv), i, ®, MVM_reg_obj); args[i++] = MVM_string_utf8_encode_C_string(tc, MVM_repr_get_str(tc, reg.o)); } args[arg_size] = NULL; INIT_ENV(); SPAWN(arg_size ? args[0] : NULL); FREE_ENV(); free(_cwd); i = 0; while(args[i]) free(args[i++]); free(args); return result; }
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env) { MVMint64 result, spawn_result; uv_process_t process = {0}; uv_process_options_t process_options = {0}; int i; char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif MVMROOT(tc, iter, { MVMString * const equal = MVM_string_ascii_decode(tc, tc->instance->VMString, STR_WITH_LEN("=")); MVMROOT(tc, equal, { MVMString *env_str; i = 0; while(MVM_iter_istrue(tc, iter)) { MVM_repr_shift_o(tc, (MVMObject *)iter); env_str = MVM_string_concatenate(tc, MVM_iterkey_s(tc, iter), equal); env_str = MVM_string_concatenate(tc, env_str, MVM_repr_get_str(tc, MVM_iterval(tc, iter))); _env[i++] = MVM_string_utf8_encode_C_string(tc, env_str); } _env[size] = NULL; }); });
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env, MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) { MVMint64 result = 0, spawn_result; uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i, process_still_running; char * const cmdin = MVM_string_utf8_c8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); char **_env = MVM_malloc((size + 1) * sizeof(char *)); MVMIter *iter; #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif MVMROOT(tc, in, { MVMROOT(tc, out, { MVMROOT(tc, err, { iter = (MVMIter *)MVM_iter(tc, env); INIT_ENV(); }); });
void MVM_coerce_istrue(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg, MVMuint8 *true_addr, MVMuint8 *false_addr, MVMuint8 flip) { MVMint64 result = 0; if (!MVM_is_null(tc, obj)) { MVMBoolificationSpec *bs = obj->st->boolification_spec; switch (bs == NULL ? MVM_BOOL_MODE_NOT_TYPE_OBJECT : bs->mode) { case MVM_BOOL_MODE_CALL_METHOD: { MVMObject *code = MVM_frame_find_invokee(tc, bs->method, NULL); MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG); if (res_reg) { /* We need to do the invocation, and set this register * the result. Then we just do the call. For the flip * case, just set up special return handler to flip * the register. */ MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_INT, inv_arg_callsite); tc->cur_frame->args[0].o = obj; if (flip) { tc->cur_frame->special_return = flip_return; tc->cur_frame->special_return_data = res_reg; } STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); } else { /* Need to set up special return hook. */ BoolMethReturnData *data = MVM_malloc(sizeof(BoolMethReturnData)); data->true_addr = true_addr; data->false_addr = false_addr; data->flip = flip; tc->cur_frame->special_return = boolify_return; tc->cur_frame->special_return_data = data; MVM_args_setup_thunk(tc, &data->res_reg, MVM_RETURN_INT, inv_arg_callsite); tc->cur_frame->args[0].o = obj; STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); } return; } case MVM_BOOL_MODE_UNBOX_INT: result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_NUM: result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0.0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY: { MVMString *str; if (!IS_CONCRETE(obj)) { result = 0; break; } str = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); result = MVM_coerce_istrue_s(tc, str); break; } case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY_OR_ZERO: { MVMString *str; MVMint64 chars; if (!IS_CONCRETE(obj)) { result = 0; break; } str = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); if (str == NULL || !IS_CONCRETE(str)) { result = 0; break; } chars = MVM_string_graphs(tc, str); result = chars == 0 || (chars == 1 && MVM_string_get_grapheme_at_nocheck(tc, str, 0) == 48) ? 0 : 1; break; } case MVM_BOOL_MODE_NOT_TYPE_OBJECT: result = !IS_CONCRETE(obj) ? 0 : 1; break; case MVM_BOOL_MODE_BIGINT: result = IS_CONCRETE(obj) ? MVM_bigint_bool(tc, obj) : 0; break; case MVM_BOOL_MODE_ITER: result = IS_CONCRETE(obj) ? MVM_iter_istrue(tc, (MVMIter *)obj) : 0; break; case MVM_BOOL_MODE_HAS_ELEMS: result = IS_CONCRETE(obj) ? MVM_repr_elems(tc, obj) != 0 : 0; break; default: MVM_exception_throw_adhoc(tc, "Invalid boolification spec mode used"); } } if (flip) result = result ? 0 : 1; if (res_reg) { res_reg->i64 = result; } else { if (result) *(tc->interp_cur_op) = true_addr; else *(tc->interp_cur_op) = false_addr; } }
/* 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; }
static void * unmarshal_callback(MVMThreadContext *tc, MVMObject *callback, MVMObject *sig_info) { MVMNativeCallbackCacheHead *callback_data_head = NULL; MVMNativeCallback **callback_data_handle; MVMString *cuid; if (!IS_CONCRETE(callback)) return NULL; /* Try to locate existing cached callback info. */ callback = MVM_frame_find_invokee(tc, callback, NULL); cuid = ((MVMCode *)callback)->body.sf->body.cuuid; MVM_string_flatten(tc, cuid); MVM_HASH_GET(tc, tc->native_callback_cache, cuid, callback_data_head); if (!callback_data_head) { callback_data_head = MVM_malloc(sizeof(MVMNativeCallbackCacheHead)); callback_data_head->head = NULL; MVM_HASH_BIND(tc, tc->native_callback_cache, cuid, callback_data_head); } callback_data_handle = &(callback_data_head->head); while (*callback_data_handle) { if ((*callback_data_handle)->target == callback) /* found it, break */ break; callback_data_handle = &((*callback_data_handle)->next); } if (!*callback_data_handle) { /* First, build the MVMNativeCallback */ MVMCallsite *cs; char *signature; MVMObject *typehash; MVMint64 num_info, i; MVMNativeCallback *callback_data; num_info = MVM_repr_elems(tc, sig_info); callback_data = MVM_malloc(sizeof(MVMNativeCallback)); callback_data->num_types = num_info; callback_data->typeinfos = MVM_malloc(num_info * sizeof(MVMint16)); callback_data->types = MVM_malloc(num_info * sizeof(MVMObject *)); callback_data->next = NULL; /* A dyncall signature looks like this: xxx)x * Argument types before the ) and return type after it. Thus, * num_info+1 must be NULL (zero-terminated string) and num_info-1 * must be the ). */ signature = MVM_malloc(num_info + 2); signature[num_info + 1] = '\0'; signature[num_info - 1] = ')'; /* We'll also build up a MoarVM callsite as we go. */ cs = MVM_malloc(sizeof(MVMCallsite)); cs->arg_flags = MVM_malloc(num_info * sizeof(MVMCallsiteEntry)); cs->arg_count = num_info - 1; cs->num_pos = num_info - 1; cs->has_flattening = 0; cs->is_interned = 0; cs->with_invocant = NULL; typehash = MVM_repr_at_pos_o(tc, sig_info, 0); callback_data->types[0] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[0] = MVM_nativecall_get_arg_type(tc, typehash, 1); signature[num_info] = get_signature_char(callback_data->typeinfos[0]); for (i = 1; i < num_info; i++) { typehash = MVM_repr_at_pos_o(tc, sig_info, i); callback_data->types[i] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[i] = MVM_nativecall_get_arg_type(tc, typehash, 0) & ~MVM_NATIVECALL_ARG_FREE_STR; signature[i - 1] = get_signature_char(callback_data->typeinfos[i]); switch (callback_data->typeinfos[i] & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: case MVM_NATIVECALL_ARG_SHORT: case MVM_NATIVECALL_ARG_INT: case MVM_NATIVECALL_ARG_LONG: case MVM_NATIVECALL_ARG_LONGLONG: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_UCHAR: case MVM_NATIVECALL_ARG_USHORT: case MVM_NATIVECALL_ARG_UINT: case MVM_NATIVECALL_ARG_ULONG: case MVM_NATIVECALL_ARG_ULONGLONG: /* TODO: should probably be UINT, when we can support that. */ cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_FLOAT: case MVM_NATIVECALL_ARG_DOUBLE: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_NUM; break; default: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_OBJ; break; } } MVM_callsite_try_intern(tc, &cs); callback_data->tc = tc; callback_data->cs = cs; callback_data->target = callback; callback_data->cb = dcbNewCallback(signature, (DCCallbackHandler *)&callback_handler, callback_data); /* Now insert the MVMCallback into the linked list. */ *callback_data_handle = callback_data; MVM_free(signature); } return (*callback_data_handle)->cb; }
static void * unmarshal_callback(MVMThreadContext *tc, MVMObject *callback, MVMObject *sig_info) { MVMNativeCallbackCacheHead *callback_data_head = NULL; MVMNativeCallback **callback_data_handle; MVMString *cuid; if (!IS_CONCRETE(callback)) return NULL; /* Try to locate existing cached callback info. */ callback = MVM_frame_find_invokee(tc, callback, NULL); cuid = ((MVMCode *)callback)->body.sf->body.cuuid; MVM_HASH_GET(tc, tc->native_callback_cache, cuid, callback_data_head); if (!callback_data_head) { callback_data_head = MVM_malloc(sizeof(MVMNativeCallbackCacheHead)); callback_data_head->head = NULL; MVM_HASH_BIND(tc, tc->native_callback_cache, cuid, callback_data_head); } callback_data_handle = &(callback_data_head->head); while (*callback_data_handle) { if ((*callback_data_handle)->target == callback) /* found it, break */ break; callback_data_handle = &((*callback_data_handle)->next); } if (!*callback_data_handle) { /* First, build the MVMNativeCallback */ MVMCallsite *cs; MVMObject *typehash; MVMint64 num_info, i; MVMNativeCallback *callback_data; /* cb is a piece of executable memory we obtain from libffi. */ void *cb; ffi_cif *cif; ffi_closure *closure; ffi_status status; num_info = MVM_repr_elems(tc, sig_info); /* We'll also build up a MoarVM callsite as we go. */ cs = MVM_calloc(1, sizeof(MVMCallsite)); cs->flag_count = num_info - 1; cs->arg_flags = MVM_malloc(cs->flag_count * sizeof(MVMCallsiteEntry)); cs->arg_count = num_info - 1; cs->num_pos = num_info - 1; cs->has_flattening = 0; cs->is_interned = 0; cs->with_invocant = NULL; callback_data = MVM_malloc(sizeof(MVMNativeCallback)); callback_data->num_types = num_info; callback_data->typeinfos = MVM_malloc(num_info * sizeof(MVMint16)); callback_data->types = MVM_malloc(num_info * sizeof(MVMObject *)); callback_data->next = NULL; cif = (ffi_cif *)MVM_malloc(sizeof(ffi_cif)); callback_data->convention = FFI_DEFAULT_ABI; callback_data->ffi_arg_types = MVM_malloc(sizeof(ffi_type *) * (cs->arg_count ? cs->arg_count : 1)); /* Collect information about the return type. */ typehash = MVM_repr_at_pos_o(tc, sig_info, 0); callback_data->types[0] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[0] = MVM_nativecall_get_arg_type(tc, typehash, 1); callback_data->ffi_ret_type = MVM_nativecall_get_ffi_type(tc, callback_data->typeinfos[0]); for (i = 1; i < num_info; i++) { typehash = MVM_repr_at_pos_o(tc, sig_info, i); callback_data->types[i] = MVM_repr_at_key_o(tc, typehash, tc->instance->str_consts.typeobj); callback_data->typeinfos[i] = MVM_nativecall_get_arg_type(tc, typehash, 0) & ~MVM_NATIVECALL_ARG_FREE_STR; callback_data->ffi_arg_types[i - 1] = MVM_nativecall_get_ffi_type(tc, callback_data->typeinfos[i]); switch (callback_data->typeinfos[i] & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: case MVM_NATIVECALL_ARG_SHORT: case MVM_NATIVECALL_ARG_INT: case MVM_NATIVECALL_ARG_LONG: case MVM_NATIVECALL_ARG_LONGLONG: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_UCHAR: case MVM_NATIVECALL_ARG_USHORT: case MVM_NATIVECALL_ARG_UINT: case MVM_NATIVECALL_ARG_ULONG: case MVM_NATIVECALL_ARG_ULONGLONG: /* TODO: should probably be UINT, when we can support that. */ cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_INT; break; case MVM_NATIVECALL_ARG_FLOAT: case MVM_NATIVECALL_ARG_DOUBLE: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_NUM; break; default: cs->arg_flags[i - 1] = MVM_CALLSITE_ARG_OBJ; break; } } MVM_callsite_try_intern(tc, &cs); callback_data->instance = tc->instance; callback_data->cs = cs; callback_data->target = callback; status = ffi_prep_cif(cif, callback_data->convention, (unsigned int)cs->arg_count, callback_data->ffi_ret_type, callback_data->ffi_arg_types); closure = ffi_closure_alloc(sizeof(ffi_closure), &cb); if (!closure) MVM_panic(1, "Unable to allocate memory for callback closure"); ffi_prep_closure_loc(closure, cif, callback_handler, callback_data, cb); callback_data->cb = cb; /* Now insert the MVMCallback into the linked list. */ *callback_data_handle = callback_data; } return (*callback_data_handle)->cb; }
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMObject *argv, MVMString *cwd, MVMObject *env, MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) { MVMint64 result = 0, spawn_result; uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = MVM_malloc((size + 1) * sizeof(char *)); const MVMuint64 arg_size = MVM_repr_elems(tc, argv); char **args = MVM_malloc((arg_size + 1) * sizeof(char *)); MVMRegister reg; i = 0; while(i < arg_size) { REPR(argv)->pos_funcs.at_pos(tc, STABLE(argv), argv, OBJECT_BODY(argv), i, ®, MVM_reg_obj); args[i++] = MVM_string_utf8_c8_encode_C_string(tc, MVM_repr_get_str(tc, reg.o)); } args[arg_size] = NULL; INIT_ENV(); setup_process_stdio(tc, in, process, &process_stdio[0], 0, flags, "spawn"); setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "spawn"); setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "spawn"); process_options.stdio = process_stdio; process_options.file = arg_size ? args[0] : NULL; process_options.args = args; process_options.cwd = _cwd; process_options.flags = UV_PROCESS_WINDOWS_HIDE; process_options.env = _env; process_options.stdio_count = 3; process_options.exit_cb = spawn_on_exit; if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) { process->data = MVM_calloc(1, sizeof(MVMint64)); uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; } else { process->data = &result; uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; else uv_run(tc->loop, UV_RUN_DEFAULT); } FREE_ENV(); MVM_free(_cwd); uv_unref((uv_handle_t *)process); i = 0; while(args[i]) MVM_free(args[i++]); MVM_free(args); return result; }
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env, MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) { MVMint64 result = 0, spawn_result; uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const cmdin = MVM_string_utf8_c8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = MVM_malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif INIT_ENV(); setup_process_stdio(tc, in, process, &process_stdio[0], 0, flags, "shell"); setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "shell"); setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "shell"); process_options.stdio = process_stdio; process_options.file = _cmd; process_options.args = args; process_options.cwd = _cwd; process_options.flags = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE; process_options.env = _env; process_options.stdio_count = 3; process_options.exit_cb = spawn_on_exit; if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) { process->data = MVM_calloc(1, sizeof(MVMint64)); uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; } else { process->data = &result; uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; else uv_run(tc->loop, UV_RUN_DEFAULT); } FREE_ENV(); MVM_free(_cwd); #ifdef _WIN32 MVM_free(_cmd); #endif MVM_free(cmdin); uv_unref((uv_handle_t *)process); return result; }
/* This works out an allocation strategy for the object. It takes care of * "inlining" storage of attributes that are natively typed, as well as * noting unbox targets. */ static void compute_allocation_strategy(MVMThreadContext *tc, MVMObject *repr_info, MVMCStructREPRData *repr_data) { /* Compute index mapping table and get flat list of attributes. */ MVMObject *flat_list = index_mapping_and_flat_list(tc, repr_info, repr_data); /* If we have no attributes in the index mapping, then just the header. */ if (repr_data->name_to_index_mapping[0].class_key == NULL) { repr_data->struct_size = 1; /* avoid 0-byte malloc */ } /* Otherwise, we need to compute the allocation strategy. */ else { /* We track the size of the struct, which is what we'll want offsets into. */ MVMint32 cur_size = 0; /* The structure itself will be the multiple of its biggest element in size. * So we keep track of that biggest element. */ MVMint32 multiple_of = 1; /* Get number of attributes and set up various counters. */ MVMint32 num_attrs = MVM_repr_elems(tc, flat_list); MVMint32 info_alloc = num_attrs == 0 ? 1 : num_attrs; MVMint32 cur_obj_attr = 0; MVMint32 cur_init_slot = 0; MVMint32 i; /* Allocate location/offset arrays and GC mark info arrays. */ repr_data->num_attributes = num_attrs; repr_data->attribute_locations = (MVMint32 *) MVM_malloc(info_alloc * sizeof(MVMint32)); repr_data->struct_offsets = (MVMint32 *) MVM_malloc(info_alloc * sizeof(MVMint32)); repr_data->flattened_stables = (MVMSTable **) MVM_calloc(info_alloc, sizeof(MVMObject *)); repr_data->member_types = (MVMObject **) MVM_calloc(info_alloc, sizeof(MVMObject *)); /* Go over the attributes and arrange their allocation. */ for (i = 0; i < num_attrs; i++) { /* Fetch its type; see if it's some kind of unboxed type. */ MVMObject *attr = MVM_repr_at_pos_o(tc, flat_list, i); MVMObject *type = MVM_repr_at_key_o(tc, attr, tc->instance->str_consts.type); MVMObject *inlined_val = MVM_repr_at_key_o(tc, attr, tc->instance->str_consts.inlined); MVMint64 inlined = !MVM_is_null(tc, inlined_val) && MVM_repr_get_int(tc, inlined_val); MVMint32 bits = sizeof(void *) * 8; MVMint32 align = ALIGNOF(void *); if (!MVM_is_null(tc, type)) { /* See if it's a type that we know how to handle in a C struct. */ const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type)); MVMint32 type_id = REPR(type)->ID; if (spec->inlineable == MVM_STORAGE_SPEC_INLINED && (spec->boxed_primitive == MVM_STORAGE_SPEC_BP_INT || spec->boxed_primitive == MVM_STORAGE_SPEC_BP_NUM)) { /* It's a boxed int or num; pretty easy. It'll just live in the * body of the struct. Instead of masking in i here (which * would be the parallel to how we handle boxed types) we * repurpose it to store the bit-width of the type, so * that get_attribute_ref can find it later. */ bits = spec->bits; align = spec->align; repr_data->attribute_locations[i] = (bits << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_IN_STRUCT; repr_data->flattened_stables[i] = STABLE(type); if (REPR(type)->initialize) { if (!repr_data->initialize_slots) repr_data->initialize_slots = (MVMint32 *) MVM_calloc(info_alloc + 1, sizeof(MVMint32)); repr_data->initialize_slots[cur_init_slot] = i; cur_init_slot++; } } else if (spec->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) { /* It's a string of some kind. */ repr_data->num_child_objs++; repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_STRING; repr_data->member_types[i] = type; repr_data->flattened_stables[i] = STABLE(type); if (REPR(type)->initialize) { if (!repr_data->initialize_slots) repr_data->initialize_slots = (MVMint32 *) MVM_calloc(info_alloc + 1, sizeof(MVMint32)); repr_data->initialize_slots[cur_init_slot] = i; cur_init_slot++; } } else if (type_id == MVM_REPR_ID_MVMCArray) { /* It's a CArray of some kind. */ repr_data->num_child_objs++; repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_CARRAY; repr_data->member_types[i] = type; } else if (type_id == MVM_REPR_ID_MVMCStruct) { /* It's a CStruct. */ repr_data->num_child_objs++; repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_CSTRUCT; repr_data->member_types[i] = type; if (inlined) { MVMCStructREPRData *cstruct_repr_data = (MVMCStructREPRData *)STABLE(type)->REPR_data; bits = cstruct_repr_data->struct_size * 8; align = cstruct_repr_data->struct_size; repr_data->attribute_locations[i] |= MVM_CSTRUCT_ATTR_INLINED; } } else if (type_id == MVM_REPR_ID_MVMCPPStruct) { /* It's a CPPStruct. */ repr_data->num_child_objs++; repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_CPPSTRUCT; repr_data->member_types[i] = type; if (inlined) { MVMCPPStructREPRData *cppstruct_repr_data = (MVMCPPStructREPRData *)STABLE(type)->REPR_data; bits = cppstruct_repr_data->struct_size * 8; align = cppstruct_repr_data->struct_size; repr_data->attribute_locations[i] |= MVM_CSTRUCT_ATTR_INLINED; } } else if (type_id == MVM_REPR_ID_MVMCUnion) { /* It's a CUnion. */ repr_data->num_child_objs++; repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_CUNION; repr_data->member_types[i] = type; if (inlined) { MVMCUnionREPRData *cunion_repr_data = (MVMCUnionREPRData *)STABLE(type)->REPR_data; bits = cunion_repr_data->struct_size * 8; align = cunion_repr_data->struct_size; repr_data->attribute_locations[i] |= MVM_CSTRUCT_ATTR_INLINED; } } else if (type_id == MVM_REPR_ID_MVMCPointer) { /* It's a CPointer. */ repr_data->num_child_objs++; repr_data->attribute_locations[i] = (cur_obj_attr++ << MVM_CSTRUCT_ATTR_SHIFT) | MVM_CSTRUCT_ATTR_CPTR; repr_data->member_types[i] = type; } else { MVM_exception_throw_adhoc(tc, "CStruct representation only handles int, num, CArray, CPointer, CStruct, CPPStruct and CUnion"); } } else { MVM_exception_throw_adhoc(tc, "CStruct representation requires the types of all attributes to be specified"); } if (bits % 8) { MVM_exception_throw_adhoc(tc, "CStruct only supports native types that are a multiple of 8 bits wide (was passed: %"PRId32")", bits); } /* Do allocation. */ /* C structure needs careful alignment. If cur_size is not aligned * to align bytes (cur_size % align), make sure it is before we * add the next element. */ if (cur_size % align) { cur_size += align - cur_size % align; } repr_data->struct_offsets[i] = cur_size; cur_size += bits / 8; if (bits / 8 > multiple_of) multiple_of = bits / 8; } /* Finally, put computed allocation size in place; it's body size plus * header size. Also number of markables and sentinels. */ if (multiple_of > sizeof(void *)) multiple_of = sizeof(void *); repr_data->struct_size = ceil((double)cur_size / (double)multiple_of) * multiple_of; if (repr_data->initialize_slots) repr_data->initialize_slots[cur_init_slot] = -1; } }
/* Enters the work loop. */ static void worker(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMObject *updated_static_frames = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); MVMObject *previous_static_frames = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); tc->instance->speshworker_thread_id = tc->thread_obj->body.thread_id; MVMROOT2(tc, updated_static_frames, previous_static_frames, { while (1) { MVMObject *log_obj; MVMuint64 start_time; unsigned int interval_id; if (MVM_spesh_debug_enabled(tc)) start_time = uv_hrtime(); log_obj = MVM_repr_shift_o(tc, tc->instance->spesh_queue); if (MVM_spesh_debug_enabled(tc)) { MVM_spesh_debug_printf(tc, "Received Logs\n" "=============\n\n" "Was waiting %dus for logs on the log queue.\n\n", (int)((uv_hrtime() - start_time) / 1000)); } if (tc->instance->main_thread->prof_data) MVM_profiler_log_spesh_start(tc); interval_id = MVM_telemetry_interval_start(tc, "spesh worker consuming a log"); uv_mutex_lock(&(tc->instance->mutex_spesh_sync)); tc->instance->spesh_working = 1; uv_mutex_unlock(&(tc->instance->mutex_spesh_sync)); tc->instance->spesh_stats_version++; if (log_obj->st->REPR->ID == MVM_REPR_ID_MVMSpeshLog) { MVMSpeshLog *sl = (MVMSpeshLog *)log_obj; MVM_telemetry_interval_annotate((uintptr_t)sl->body.thread->body.tc, interval_id, "from this thread"); MVMROOT(tc, sl, { MVMThreadContext *stc; MVMuint32 i; MVMuint32 n; /* Update stats, and if we're logging dump each of them. */ tc->instance->spesh_stats_version++; if (MVM_spesh_debug_enabled(tc)) start_time = uv_hrtime(); MVM_spesh_stats_update(tc, sl, updated_static_frames); n = MVM_repr_elems(tc, updated_static_frames); if (MVM_spesh_debug_enabled(tc)) { MVM_spesh_debug_printf(tc, "Statistics Updated\n" "==================\n" "%d frames had their statistics updated in %dus.\n\n", (int)n, (int)((uv_hrtime() - start_time) / 1000)); for (i = 0; i < n; i++) { char *dump = MVM_spesh_dump_stats(tc, (MVMStaticFrame* ) MVM_repr_at_pos_o(tc, updated_static_frames, i)); MVM_spesh_debug_printf(tc, "%s==========\n\n", dump); MVM_free(dump); } } MVM_telemetry_interval_annotate((uintptr_t)n, interval_id, "stats for this many frames"); GC_SYNC_POINT(tc); /* Form a specialization plan. */ if (MVM_spesh_debug_enabled(tc)) start_time = uv_hrtime(); tc->instance->spesh_plan = MVM_spesh_plan(tc, updated_static_frames); if (MVM_spesh_debug_enabled(tc)) { n = tc->instance->spesh_plan->num_planned; MVM_spesh_debug_printf(tc, "Specialization Plan\n" "===================\n" "%u specialization(s) will be produced (planned in %dus).\n\n", n, (int)((uv_hrtime() - start_time) / 1000)); for (i = 0; i < n; i++) { char *dump = MVM_spesh_dump_planned(tc, &(tc->instance->spesh_plan->planned[i])); MVM_spesh_debug_printf(tc, "%s==========\n\n", dump); MVM_free(dump); } } MVM_telemetry_interval_annotate((uintptr_t)tc->instance->spesh_plan->num_planned, interval_id, "this many specializations planned"); GC_SYNC_POINT(tc); /* Implement the plan and then discard it. */ n = tc->instance->spesh_plan->num_planned; for (i = 0; i < n; i++) { MVM_spesh_candidate_add(tc, &(tc->instance->spesh_plan->planned[i])); GC_SYNC_POINT(tc); } MVM_spesh_plan_destroy(tc, tc->instance->spesh_plan); tc->instance->spesh_plan = NULL; /* Clear up stats that didn't get updated for a while, * then add frames updated this time into the previously * updated array. */ MVM_spesh_stats_cleanup(tc, previous_static_frames); n = MVM_repr_elems(tc, updated_static_frames); for (i = 0; i < n; i++) MVM_repr_push_o(tc, previous_static_frames, MVM_repr_at_pos_o(tc, updated_static_frames, i)); /* Clear updated static frames array. */ MVM_repr_pos_set_elems(tc, updated_static_frames, 0); /* Allow the sending thread to produce more logs again, * putting a new spesh log in place if needed. */ stc = sl->body.thread->body.tc; if (stc && !sl->body.was_compunit_bumped) if (MVM_incr(&(stc->spesh_log_quota)) == 0) { stc->spesh_log = MVM_spesh_log_create(tc, sl->body.thread); MVM_telemetry_timestamp(stc, "logging restored after quota had run out"); } /* If needed, signal sending thread that it can continue. */ if (sl->body.block_mutex) { uv_mutex_lock(sl->body.block_mutex); MVM_store(&(sl->body.completed), 1); uv_cond_signal(sl->body.block_condvar); uv_mutex_unlock(sl->body.block_mutex); } { MVMSpeshLogEntry *entries = sl->body.entries; sl->body.entries = NULL; MVM_free(entries); } }); } else if (MVM_is_null(tc, log_obj)) {
MVMObject * MVM_file_openpipe(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env, MVMString *err_path) { MVMint64 spawn_result = 0; uv_process_t *process = calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; int status; int readable = 1; uv_pipe_t *out, *in; char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; { MVMint64 len = strlen(cmdin); MVMint64 i; for (i = 0; i < len; i++) if (cmdin[i] == '/') cmdin[i] = '\\'; } args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif INIT_ENV(); /* Making openpipe distinguish between :rp and :wp and all other options * is left as an excercise for the reader. readable = strncmp(cmdin, "/usr/bin/wc", 11) != 0; */ if (readable) { /* We want to read from the child's stdout. */ out = malloc(sizeof(uv_pipe_t)); uv_pipe_init(tc->loop, out, 0); uv_pipe_open(out, 0); process_stdio[0].flags = UV_INHERIT_FD; // child's stdin process_stdio[0].data.fd = 0; process_stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; // child's stdout process_stdio[1].data.stream = (uv_stream_t*)out; } else { /* We want to print to the child's stdin. */ in = malloc(sizeof(uv_pipe_t)); uv_pipe_init(tc->loop, in, 0); uv_pipe_open(in, 1); process_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; // child's stdin process_stdio[0].data.stream = (uv_stream_t*)in; process_stdio[1].flags = UV_INHERIT_FD; // child's stdout process_stdio[1].data.fd = 1; } process_stdio[2].flags = UV_INHERIT_FD; // child's stderr process_stdio[2].data.fd = 2; process_options.stdio = process_stdio; process_options.file = _cmd; process_options.args = args; process_options.cwd = _cwd; process_options.flags = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE; process_options.env = _env; process_options.stdio_count = 3; process_options.exit_cb = spawn_on_exit; uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) { FREE_ENV(); free(_cwd); free(cmdin); uv_unref((uv_handle_t *)process); MVM_exception_throw_adhoc(tc, "Failed to open pipe: %d", errno); } FREE_ENV(); free(_cwd); free(cmdin); uv_unref((uv_handle_t *)process); return MVM_io_syncpipe(tc, (uv_stream_t *)(readable ? out : in), process); }
void MVM_coerce_istrue(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg, MVMuint8 *true_addr, MVMuint8 *false_addr, MVMuint8 flip) { MVMint64 result; if (obj == NULL) { result = 0; } else { MVMBoolificationSpec *bs = obj->st->boolification_spec; switch (bs == NULL ? MVM_BOOL_MODE_NOT_TYPE_OBJECT : bs->mode) { case MVM_BOOL_MODE_CALL_METHOD: if (res_reg) { /* We need to do the invocation, and set this register * the result. Then we just do the call. For the flip * case, just set up special return handler to flip * the register. */ MVMObject *code = MVM_frame_find_invokee(tc, bs->method); tc->cur_frame->return_value = res_reg; tc->cur_frame->return_type = MVM_RETURN_INT; tc->cur_frame->return_address = *(tc->interp_cur_op); tc->cur_frame->args[0].o = obj; if (flip) { tc->cur_frame->special_return = flip_return; tc->cur_frame->special_return_data = res_reg; } STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args); } else { /* Need to set up special return hook. */ MVMObject *code = MVM_frame_find_invokee(tc, bs->method); BoolMethReturnData *data = malloc(sizeof(BoolMethReturnData)); data->true_addr = true_addr; data->false_addr = false_addr; data->flip = flip; tc->cur_frame->special_return = boolify_return; tc->cur_frame->special_return_data = data; tc->cur_frame->return_value = &data->res_reg; tc->cur_frame->return_type = MVM_RETURN_INT; tc->cur_frame->return_address = *(tc->interp_cur_op); tc->cur_frame->args[0].o = obj; STABLE(code)->invoke(tc, code, get_inv_callsite(), tc->cur_frame->args); return; } break; case MVM_BOOL_MODE_UNBOX_INT: result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs->get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_NUM: result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs->get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0.0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY: result = !IS_CONCRETE(obj) || NUM_GRAPHS(REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj))) == 0 ? 0 : 1; break; case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY_OR_ZERO: { MVMString *str; if (!IS_CONCRETE(obj)) { result = 0; break; } str = REPR(obj)->box_funcs->get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); result = MVM_coerce_istrue_s(tc, str); break; } case MVM_BOOL_MODE_NOT_TYPE_OBJECT: result = !IS_CONCRETE(obj) ? 0 : 1; break; case MVM_BOOL_MODE_ITER: result = IS_CONCRETE(obj) ? MVM_iter_istrue(tc, (MVMIter *)obj) : 0; break; case MVM_BOOL_MODE_HAS_ELEMS: result = IS_CONCRETE(obj) ? MVM_repr_elems(tc, obj) != 0 : 0; break; default: MVM_exception_throw_adhoc(tc, "Invalid boolification spec mode used"); } } if (flip) result = result ? 0 : 1; if (res_reg) { res_reg->i64 = result; } else { if (result) *(tc->interp_cur_op) = true_addr; else *(tc->interp_cur_op) = false_addr; } }