MVMObject * snapshot_to_mvm_object(MVMThreadContext *tc, MVMHeapSnapshot *s) { MVMObject *snapshot = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_hash_type); MVM_repr_bind_key_o(tc, snapshot, vmstr(tc, "collectables"), collectables_str(tc, s)); MVM_repr_bind_key_o(tc, snapshot, vmstr(tc, "references"), references_str(tc, s)); return snapshot; }
/* Dumps data from a single thread. */ static MVMObject * dump_thread_data(MVMThreadContext *tc, ProfDumpStrs *pds, const MVMProfileThreadData *ptd) { MVMObject *thread_hash = new_hash(tc); MVMObject *thread_gcs = new_array(tc); MVMuint32 i; /* Add time. */ MVM_repr_bind_key_o(tc, thread_hash, pds->total_time, box_i(tc, (ptd->end_time - ptd->start_time) / 1000)); /* Add call graph. */ if (ptd->call_graph) MVM_repr_bind_key_o(tc, thread_hash, pds->call_graph, dump_call_graph_node(tc, pds, ptd->call_graph)); /* Add GCs. */ for (i = 0; i < ptd->num_gcs; i++) { MVMObject *gc_hash = new_hash(tc); MVM_repr_bind_key_o(tc, gc_hash, pds->time, box_i(tc, ptd->gcs[i].time / 1000)); MVM_repr_bind_key_o(tc, gc_hash, pds->full, box_i(tc, ptd->gcs[i].full)); MVM_repr_bind_key_o(tc, gc_hash, pds->cleared_bytes, box_i(tc, ptd->gcs[i].cleared_bytes)); MVM_repr_bind_key_o(tc, gc_hash, pds->retained_bytes, box_i(tc, ptd->gcs[i].retained_bytes)); MVM_repr_bind_key_o(tc, gc_hash, pds->promoted_bytes, box_i(tc, ptd->gcs[i].promoted_bytes)); MVM_repr_bind_key_o(tc, gc_hash, pds->gen2_roots, box_i(tc, ptd->gcs[i].num_gen2roots)); MVM_repr_push_o(tc, thread_gcs, gc_hash); } MVM_repr_bind_key_o(tc, thread_hash, pds->gcs, thread_gcs); /* Add spesh time. */ MVM_repr_bind_key_o(tc, thread_hash, pds->spesh_time, box_i(tc, ptd->spesh_time / 1000)); return thread_hash; }
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; }
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; }
/* Adds a method. */ static void add_method(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMObject *self, *method, *method_table; MVMString *name; /* Get arguments. */ MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); MVM_args_checkarity(tc, &arg_ctx, 4, 4); self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; name = MVM_args_get_pos_str(tc, &arg_ctx, 2, MVM_ARG_REQUIRED).arg.s; method = MVM_args_get_pos_obj(tc, &arg_ctx, 3, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); if (!self || !IS_CONCRETE(self) || REPR(self)->ID != MVM_REPR_ID_KnowHOWREPR) MVM_exception_throw_adhoc(tc, "KnowHOW methods must be called on object instance with REPR KnowHOWREPR"); /* Add to method table. */ method_table = ((MVMKnowHOWREPR *)self)->body.methods; MVM_repr_bind_key_o(tc, method_table, name, method); /* Return added method as result. */ MVM_args_set_result_obj(tc, method, MVM_RETURN_CURRENT_FRAME); }
/* 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; }
/* Dumps a call graph node. */ static MVMObject * dump_call_graph_node(MVMThreadContext *tc, ProfDumpStrs *pds, const MVMProfileCallNode *pcn) { MVMObject *node_hash = new_hash(tc); MVMuint32 i; /* Let's see if we're dealing with a native call or a regular moar call */ if (pcn->sf) { /* Try to resolve the code filename and line number. */ MVMBytecodeAnnotation *annot = MVM_bytecode_resolve_annotation(tc, &(pcn->sf->body), 0); MVMint32 fshi = annot ? (MVMint32)annot->filename_string_heap_index : -1; /* Add name of code object. */ MVM_repr_bind_key_o(tc, node_hash, pds->name, box_s(tc, pcn->sf->body.name)); /* Add line number and file name. */ if (fshi >= 0 && fshi < pcn->sf->body.cu->body.num_strings) MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, MVM_cu_string(tc, pcn->sf->body.cu, fshi))); else if (pcn->sf->body.cu->body.filename) MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, pcn->sf->body.cu->body.filename)); else MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, tc->instance->str_consts.empty)); MVM_repr_bind_key_o(tc, node_hash, pds->line, box_i(tc, annot ? (MVMint32)annot->line_number : -1)); MVM_free(annot); /* Use static frame memory address to get a unique ID. */ MVM_repr_bind_key_o(tc, node_hash, pds->id, box_i(tc, (MVMint64)pcn->sf)); } else { MVMString *function_name_string = MVM_string_utf8_c8_decode(tc, tc->instance->VMString, pcn->native_target_name, strlen(pcn->native_target_name)); MVM_repr_bind_key_o(tc, node_hash, pds->name, box_s(tc, function_name_string)); MVM_repr_bind_key_o(tc, node_hash, pds->file, box_s(tc, pds->native_lib)); MVM_repr_bind_key_o(tc, node_hash, pds->line, box_i(tc, -2)); /* Use the address of the name string as unique ID. a hack, but oh well. */ MVM_repr_bind_key_o(tc, node_hash, pds->id, box_i(tc, (MVMint64)pcn->native_target_name)); } /* Entry counts. */ if (pcn->total_entries) MVM_repr_bind_key_o(tc, node_hash, pds->entries, box_i(tc, pcn->total_entries)); if (pcn->specialized_entries) MVM_repr_bind_key_o(tc, node_hash, pds->spesh_entries, box_i(tc, pcn->specialized_entries)); if (pcn->jit_entries) MVM_repr_bind_key_o(tc, node_hash, pds->jit_entries, box_i(tc, pcn->jit_entries)); if (pcn->inlined_entries) MVM_repr_bind_key_o(tc, node_hash, pds->inlined_entries, box_i(tc, pcn->inlined_entries)); /* Total (inclusive) time. */ MVM_repr_bind_key_o(tc, node_hash, pds->inclusive_time, box_i(tc, pcn->total_time / 1000)); /* OSR and deopt counts. */ if (pcn->osr_count) MVM_repr_bind_key_o(tc, node_hash, pds->osr, box_i(tc, pcn->osr_count)); if (pcn->deopt_one_count) MVM_repr_bind_key_o(tc, node_hash, pds->deopt_one, box_i(tc, pcn->deopt_one_count)); if (pcn->deopt_all_count) MVM_repr_bind_key_o(tc, node_hash, pds->deopt_all, box_i(tc, pcn->deopt_all_count)); /* Visit successors in the call graph, dumping them and working out the * exclusive time. */ if (pcn->num_succ) { MVMObject *callees = new_array(tc); MVMuint64 exclusive_time = pcn->total_time; for (i = 0; i < pcn->num_succ; i++) { MVM_repr_push_o(tc, callees, dump_call_graph_node(tc, pds, pcn->succ[i])); exclusive_time -= pcn->succ[i]->total_time; } MVM_repr_bind_key_o(tc, node_hash, pds->exclusive_time, box_i(tc, exclusive_time / 1000)); MVM_repr_bind_key_o(tc, node_hash, pds->callees, callees); } else { MVM_repr_bind_key_o(tc, node_hash, pds->exclusive_time, box_i(tc, pcn->total_time / 1000)); } if (pcn->num_alloc) { /* Emit allocations. */ MVMObject *alloc_list = new_array(tc); MVM_repr_bind_key_o(tc, node_hash, pds->allocations, alloc_list); for (i = 0; i < pcn->num_alloc; i++) { MVMObject *alloc_info = new_hash(tc); MVMProfileAllocationCount *alloc = &pcn->alloc[i]; MVMObject *type = pcn->alloc[i].type; MVM_repr_bind_key_o(tc, alloc_info, pds->id, box_i(tc, (MVMint64)type)); MVM_repr_bind_key_o(tc, alloc_info, pds->type, type); if (alloc->allocations_spesh) MVM_repr_bind_key_o(tc, alloc_info, pds->spesh, box_i(tc, alloc->allocations_spesh)); if (alloc->allocations_jit) MVM_repr_bind_key_o(tc, alloc_info, pds->jit, box_i(tc, alloc->allocations_jit)); MVM_repr_bind_key_o(tc, alloc_info, pds->count, box_i(tc, alloc->allocations_interp + alloc->allocations_spesh + alloc->allocations_jit)); MVM_repr_push_o(tc, alloc_list, alloc_info); } } return node_hash; }
/* Composes the meta-object. */ static void compose(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMObject *self, *type_obj, *method_table, *attributes, *BOOTArray, *BOOTHash, *repr_info_hash, *repr_info, *type_info, *attr_info_list, *parent_info; MVMuint64 num_attrs, i; MVMInstance *instance = tc->instance; /* Get arguments. */ MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); MVM_args_checkarity(tc, &arg_ctx, 2, 2); self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; type_obj = MVM_args_get_pos_obj(tc, &arg_ctx, 1, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); if (!self || !IS_CONCRETE(self) || REPR(self)->ID != MVM_REPR_ID_KnowHOWREPR) MVM_exception_throw_adhoc(tc, "KnowHOW methods must be called on object instance with REPR KnowHOWREPR"); /* Fill out STable. */ method_table = ((MVMKnowHOWREPR *)self)->body.methods; MVM_ASSIGN_REF(tc, &(STABLE(type_obj)->header), STABLE(type_obj)->method_cache, method_table); STABLE(type_obj)->mode_flags = MVM_METHOD_CACHE_AUTHORITATIVE; STABLE(type_obj)->type_check_cache_length = 1; STABLE(type_obj)->type_check_cache = MVM_malloc(sizeof(MVMObject *)); MVM_ASSIGN_REF(tc, &(STABLE(type_obj)->header), STABLE(type_obj)->type_check_cache[0], type_obj); attributes = ((MVMKnowHOWREPR *)self)->body.attributes; /* Next steps will allocate, so make sure we keep hold of the type * object and ourself. */ MVM_gc_root_temp_push(tc, (MVMCollectable **)&attributes); MVM_gc_root_temp_push(tc, (MVMCollectable **)&type_obj); /* Use any attribute information to produce attribute protocol * data. The protocol consists of an array... */ BOOTArray = instance->boot_types.BOOTArray; BOOTHash = instance->boot_types.BOOTHash; MVM_gc_root_temp_push(tc, (MVMCollectable **)&BOOTArray); MVM_gc_root_temp_push(tc, (MVMCollectable **)&BOOTHash); repr_info = REPR(BOOTArray)->allocate(tc, STABLE(BOOTArray)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&repr_info); /* ...which contains an array per MRO entry (just us)... */ type_info = REPR(BOOTArray)->allocate(tc, STABLE(BOOTArray)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&type_info); MVM_repr_push_o(tc, repr_info, type_info); /* ...which in turn contains this type... */ MVM_repr_push_o(tc, type_info, type_obj); /* ...then an array of hashes per attribute... */ attr_info_list = REPR(BOOTArray)->allocate(tc, STABLE(BOOTArray)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_info_list); MVM_repr_push_o(tc, type_info, attr_info_list); num_attrs = REPR(attributes)->elems(tc, STABLE(attributes), attributes, OBJECT_BODY(attributes)); for (i = 0; i < num_attrs; i++) { MVMObject *attr_info = REPR(BOOTHash)->allocate(tc, STABLE(BOOTHash)); MVMKnowHOWAttributeREPR *attribute = (MVMKnowHOWAttributeREPR *) MVM_repr_at_pos_o(tc, attributes, i); MVMROOT(tc, attr_info, { MVMROOT(tc, attribute, { if (REPR((MVMObject *)attribute)->ID != MVM_REPR_ID_KnowHOWAttributeREPR) MVM_exception_throw_adhoc(tc, "KnowHOW attributes must use KnowHOWAttributeREPR"); MVM_repr_init(tc, attr_info); MVM_repr_bind_key_o(tc, attr_info, instance->str_consts.name, (MVMObject *)attribute->body.name); MVM_repr_bind_key_o(tc, attr_info, instance->str_consts.type, attribute->body.type); if (attribute->body.box_target) { /* Merely having the key serves as a "yes". */ MVM_repr_bind_key_o(tc, attr_info, instance->str_consts.box_target, attr_info); } MVM_repr_push_o(tc, attr_info_list, attr_info); }); });
/* Returns a list of hashes containing file, line, sub and annotations. */ MVMObject * MVM_exception_backtrace(MVMThreadContext *tc, MVMObject *ex_obj) { MVMFrame *cur_frame; MVMObject *arr = NULL, *annotations = NULL, *row = NULL, *value = NULL; MVMuint32 count = 0; MVMString *k_file = NULL, *k_line = NULL, *k_sub = NULL, *k_anno = NULL; if (IS_CONCRETE(ex_obj) && REPR(ex_obj)->ID == MVM_REPR_ID_MVMException) cur_frame = ((MVMException *)ex_obj)->body.origin; else MVM_exception_throw_adhoc(tc, "Op 'backtrace' needs an exception object"); MVM_gc_root_temp_push(tc, (MVMCollectable **)&arr); MVM_gc_root_temp_push(tc, (MVMCollectable **)&annotations); MVM_gc_root_temp_push(tc, (MVMCollectable **)&row); MVM_gc_root_temp_push(tc, (MVMCollectable **)&value); MVM_gc_root_temp_push(tc, (MVMCollectable **)&k_file); MVM_gc_root_temp_push(tc, (MVMCollectable **)&k_line); MVM_gc_root_temp_push(tc, (MVMCollectable **)&k_sub); MVM_gc_root_temp_push(tc, (MVMCollectable **)&k_anno); k_file = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "file"); k_line = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "line"); k_sub = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "sub"); k_anno = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "annotations"); arr = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTArray); while (cur_frame != NULL) { MVMuint8 *cur_op = count ? cur_frame->return_address : cur_frame->throw_address; MVMuint32 offset = cur_op - cur_frame->effective_bytecode; MVMBytecodeAnnotation *annot = MVM_bytecode_resolve_annotation(tc, &cur_frame->static_info->body, offset > 0 ? offset - 1 : 0); MVMint32 fshi = annot ? (MVMint32)annot->filename_string_heap_index : -1; char *line_number = malloc(16); snprintf(line_number, 16, "%d", annot ? annot->line_number : 1); /* annotations hash will contain "file" and "line" */ annotations = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTHash); /* file */ if (fshi >= 0 && fshi < cur_frame->static_info->body.cu->body.num_strings) value = MVM_repr_box_str(tc, MVM_hll_current(tc)->str_box_type, cur_frame->static_info->body.cu->body.strings[fshi]); else value = MVM_repr_box_str(tc, MVM_hll_current(tc)->str_box_type, cur_frame->static_info->body.cu->body.filename); MVM_repr_bind_key_o(tc, annotations, k_file, value); /* line */ value = (MVMObject *)MVM_string_ascii_decode_nt(tc, tc->instance->VMString, line_number); value = MVM_repr_box_str(tc, MVM_hll_current(tc)->str_box_type, (MVMString *)value); MVM_repr_bind_key_o(tc, annotations, k_line, value); free(line_number); /* row will contain "sub" and "annotations" */ row = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTHash); MVM_repr_bind_key_o(tc, row, k_sub, cur_frame->code_ref); MVM_repr_bind_key_o(tc, row, k_anno, annotations); MVM_repr_push_o(tc, arr, row); cur_frame = cur_frame->caller; while (cur_frame && cur_frame->static_info->body.is_thunk) cur_frame = cur_frame->caller; count++; } MVM_gc_root_temp_pop_n(tc, 8); return arr; }