/* Gets the flag for whether to free a string after a call or not. */ static MVMint16 get_str_free_flag(MVMThreadContext *tc, MVMObject *info) { MVMString *flag = tc->instance->str_consts.free_str; if (MVM_repr_exists_key(tc, info, flag)) if (!MVM_repr_get_int(tc, MVM_repr_at_key_o(tc, info, flag))) return MVM_NATIVECALL_ARG_NO_FREE_STR; return MVM_NATIVECALL_ARG_FREE_STR; }
/* Gets the flag for whether an arg is rw or not. */ static MVMint16 get_rw_flag(MVMThreadContext *tc, MVMObject *info) { MVMString *flag = tc->instance->str_consts.rw; if (MVM_repr_exists_key(tc, info, flag)) { if (MVM_repr_get_int(tc, MVM_repr_at_key_o(tc, info, flag))) return MVM_NATIVECALL_ARG_RW; } return MVM_NATIVECALL_ARG_NO_RW; }
/* Helper for finding a slot number. */ static MVMint32 try_get_slot(MVMThreadContext *tc, MVMCStructREPRData *repr_data, MVMObject *class_key, MVMString *name) { if (repr_data->name_to_index_mapping) { MVMCStructNameMap *cur_map_entry = repr_data->name_to_index_mapping; while (cur_map_entry->class_key != NULL) { if (cur_map_entry->class_key == class_key) { MVMObject *slot_obj = MVM_repr_at_key_o(tc, cur_map_entry->name_map, name); if (IS_CONCRETE(slot_obj)) return MVM_repr_get_int(tc, slot_obj); break; } cur_map_entry++; } } return -1; }
static void rakudo_scalar_fetch_i(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) { res->i64 = MVM_repr_get_int(tc, ((Rakudo_Scalar *)cont)->value); }
/* 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; } }
/* Dumps a table of all logged values */ static void dump_log_values(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g) { MVMint16 log_index; MVMint16 seen_table_size = g->num_log_slots * MVM_SPESH_LOG_RUNS; size_t ds_pos_before = tell_ds(ds); MVMint16 interesting = 0; MVMCollectable **seen_table = alloca(sizeof(MVMCollectable *) *seen_table_size); memset(seen_table, 0, sizeof(MVMCollectable *) * seen_table_size); append(ds, "Logged values:\n"); for (log_index = 0; log_index < g->num_log_slots; log_index++) { MVMint16 run_index; appendf(ds, " % 3d ", log_index); for (run_index = 0; run_index < MVM_SPESH_LOG_RUNS; run_index++) { MVMuint16 log_slot = log_index * MVM_SPESH_LOG_RUNS + run_index; MVMCollectable *log_obj = g->log_slots[log_slot]; MVMint16 log_obj_idx; if (log_obj) { for (log_obj_idx = 0; log_obj_idx < seen_table_size; log_obj_idx++) { if (seen_table[log_obj_idx] == log_obj) { break; } else if (seen_table[log_obj_idx] == 0) { seen_table[log_obj_idx] = log_obj; break; } } appendf(ds, "% 4d ", log_obj_idx + 1); interesting = 1; } else { appendf(ds, "%4s ", "_"); } } append(ds, "\n"); } append(ds, "\n"); for (log_index = 0; log_index < seen_table_size && seen_table[log_index]; log_index++) { appendf(ds, " %d: %p", log_index + 1, seen_table[log_index]); if (STABLE(seen_table[log_index])->REPR->ID == MVM_REPR_ID_P6int) { if (IS_CONCRETE(seen_table[log_index])) appendf(ds, " P6int(%"PRId64")", MVM_repr_get_int(tc, (MVMObject*)seen_table[log_index])); else append(ds, " P6int(type object)"); } else { append(ds, " "); append(ds, (char *)STABLE(seen_table[log_index])->REPR->name); if (!IS_CONCRETE(seen_table[log_index])) append(ds, "(type object)"); if (STABLE(seen_table[log_index])->debug_name) { appendf(ds, " debugname: %s", STABLE(seen_table[log_index])->debug_name); } } append(ds, "\n"); } append(ds, "\n"); if (!interesting) { rewind_ds(ds, ds_pos_before); } }