void MVM_6model_can_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { MVMObject *HOW, *find_method, *code; MVMCallsite *findmeth_callsite; MVMint64 can_cached = MVM_6model_can_method_cache_only(tc, obj, name); if (can_cached == 0 || can_cached == 1) { res->i64 = can_cached; return; } /* If no method in cache and the cache is not authoritative, need to make * a late-bound call to find_method. */ HOW = MVM_6model_get_how(tc, STABLE(obj)); find_method = MVM_6model_find_method_cache_only(tc, HOW, tc->instance->str_consts.find_method); if (MVM_is_null(tc, find_method)) { /* This'll count as a "no"... */ res->i64 = 0; return; } /* Set up the call, using the result register as the target. A little bad * as we're really talking about */ code = MVM_frame_find_invokee(tc, find_method, NULL); findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD); MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite); tc->cur_frame->special_return = late_bound_can_return; tc->cur_frame->special_return_data = res; tc->cur_frame->args[0].o = HOW; tc->cur_frame->args[1].o = obj; tc->cur_frame->args[2].s = name; STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args); }
/* Creates a new type with this HOW as its meta-object. */ static void new_type(PARROT_INTERP, PMC *nci) { PMC * unused; /* We first create a new HOW instance. */ PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0); PMC *HOW = REPR(self)->allocate(interp, STABLE(self)); /* See if we have a representation name; if not default to P6opaque. */ STRING *repr_name = VTABLE_exists_keyed_str(interp, capture, repr_str) ? VTABLE_get_string_keyed_str(interp, capture, repr_str) : p6opaque_str; /* Create a new type object of the desired REPR. (Note that we can't * default to KnowHOWREPR here, since it doesn't know how to actually * store attributes, it's just for bootstrapping knowhow's. */ REPROps *repr_to_use = REPR_get_by_name(interp, repr_name); PMC *type_object = repr_to_use->type_object_for(interp, HOW); /* See if we were given a name; put it into the meta-object if so. */ STRING *name = VTABLE_exists_keyed_str(interp, capture, name_str) ? VTABLE_get_string_keyed_str(interp, capture, name_str) : empty_str; REPR(HOW)->initialize(interp, STABLE(HOW), OBJECT_BODY(HOW)); ((KnowHOWREPRInstance *)PMC_data(HOW))->body.name = name; PARROT_GC_WRITE_BARRIER(interp, HOW); /* Set .WHO to an empty hash. */ STABLE(type_object)->WHO = Parrot_pmc_new(interp, enum_class_Hash); PARROT_GC_WRITE_BARRIER(interp, STABLE_PMC(type_object)); /* Put it into capture to act as return value. */ unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", type_object); }
/* Binds the given value to the specified attribute. */ static void bind_attribute_boxed(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint, PMC *value) { P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data; INTVAL slot; /* Try the slot allocation first. */ slot = hint >= 0 && !(repr_data->mi) ? hint : try_get_slot(interp, repr_data, class_handle, name); if (slot >= 0) { STable *st = repr_data->flattened_stables[slot]; if (st) { if (value->vtable->base_type == smo_id && st == STABLE(value)) st->REPR->copy_to(interp, st, OBJECT_BODY(value), (char *)data + repr_data->attribute_offsets[slot]); else Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "Type mismatch when storing value to attribute '%Ss' on class '%Ss'", name, VTABLE_get_string(interp, introspection_call(interp, class_handle, STABLE(class_handle)->HOW, Parrot_str_new_constant(interp, "name"), 0))); } else { set_pmc_at_offset(data, repr_data->attribute_offsets[slot], value); } } else { /* Otherwise, complain that the attribute doesn't exist. */ no_such_attribute(interp, "bind", class_handle, name); } }
MVMObject * MVM_repr_alloc_init(MVMThreadContext *tc, MVMObject *type) { MVMObject *obj = REPR(type)->allocate(tc, STABLE(type)); if (REPR(obj)->initialize) { MVMROOT(tc, obj, { REPR(obj)->initialize(tc, STABLE(obj), obj, OBJECT_BODY(obj)); });
static void code_pair_store_internal(MVMThreadContext *tc, MVMObject *cont, MVMRegister value, MVMCallsite *cs) { CodePairContData *data = (CodePairContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->store_code, NULL); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, cs); tc->cur_frame->args[0].o = cont; tc->cur_frame->args[1] = value; STABLE(code)->invoke(tc, code, cs, tc->cur_frame->args); }
static void code_pair_fetch_internal(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res, MVMReturnType res_type) { CodePairContData *data = (CodePairContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->fetch_code, NULL); MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG); MVM_args_setup_thunk(tc, res, res_type, inv_arg_callsite); tc->cur_frame->args[0].o = cont; STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); }
static void rakudo_scalar_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *value) { RakudoContData *data = (RakudoContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->store, NULL); MVMCallsite *cs = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TWO_OBJ); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, cs); tc->cur_frame->args[0].o = cont; tc->cur_frame->args[1].o = value; STABLE(code)->invoke(tc, code, cs, tc->cur_frame->args); }
/* Attribute new method. */ static void attr_new(PARROT_INTERP, PMC *nci) { PMC * unused; PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); PMC *type = VTABLE_get_pmc_keyed_int(interp, capture, 0); STRING *name = VTABLE_get_string_keyed_str(interp, capture, name_str); PMC *self = REPR(type)->allocate(interp, STABLE(type)); REPR(self)->box_funcs->set_str(interp, STABLE(self), OBJECT_BODY(self), name); unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", self); }
static void code_pair_fetch(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) { CodePairContData *data = (CodePairContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->fetch_code, NULL); MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, &fetch_arg_callsite); tc->cur_frame->args[0].o = cont; STABLE(code)->invoke(tc, code, &fetch_arg_callsite, tc->cur_frame->args); }
/* Determines if there's a matching spesh candidate for a callee and a given * set of argument info. */ static MVMint32 try_find_spesh_candidate(MVMThreadContext *tc, MVMCode *code, MVMSpeshCallInfo *arg_info) { MVMStaticFrameBody *sfb = &(code->body.sf->body); MVMint32 num_spesh = sfb->num_spesh_candidates; MVMint32 i, j; for (i = 0; i < num_spesh; i++) { MVMSpeshCandidate *cand = &sfb->spesh_candidates[i]; if (cand->cs == arg_info->cs) { /* Matching callsite, now see if we have enough information to * test the guards. */ MVMint32 guard_failed = 0; for (j = 0; j < cand->num_guards; j++) { MVMint32 slot = cand->guards[j].slot; MVMSpeshFacts *facts = slot < MAX_ARGS_FOR_OPT ? arg_info->arg_facts[slot] : NULL; MVMSTable *want_st = (MVMSTable *)cand->guards[j].match; if (!facts) { guard_failed = 1; break; } switch (cand->guards[j].kind) { case MVM_SPESH_GUARD_CONC: if (!(facts->flags & MVM_SPESH_FACT_CONCRETE) || !(facts->flags & MVM_SPESH_FACT_KNOWN_TYPE) || STABLE(facts->type) != want_st) guard_failed = 1; break; case MVM_SPESH_GUARD_TYPE: if (!(facts->flags & MVM_SPESH_FACT_TYPEOBJ) || !(facts->flags & MVM_SPESH_FACT_KNOWN_TYPE) || STABLE(facts->type) != want_st) guard_failed = 1; break; case MVM_SPESH_GUARD_DC_CONC: if (!(facts->flags & MVM_SPESH_FACT_DECONT_CONCRETE) || !(facts->flags & MVM_SPESH_FACT_KNOWN_DECONT_TYPE) || STABLE(facts->decont_type) != want_st) guard_failed = 1; break; case MVM_SPESH_GUARD_DC_TYPE: if (!(facts->flags & MVM_SPESH_FACT_DECONT_TYPEOBJ) || !(facts->flags & MVM_SPESH_FACT_KNOWN_DECONT_TYPE) || STABLE(facts->decont_type) != want_st) guard_failed = 1; break; default: guard_failed = 1; break; } if (guard_failed) break; } if (!guard_failed) return i; } } return -1; }
/* Sets up a very simple attribute meta-object. Just supports having a * name, and even uses the P6str representation to store it, so that's * really all that it supports. */ PMC * SixModelObject_setup_knowhow_attribute(PARROT_INTERP, PMC *sc, PMC *knowhow) { PMC *old_ctx, *cappy, *meth, *knowhow_attr, *how; /* Create a new KnowHOWAttribute type using P6str repr.. */ meth = STABLE(knowhow)->find_method(interp, knowhow, Parrot_str_new_constant(interp, "new_type"), NO_HINT); old_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, knowhow); VTABLE_set_string_keyed_str(interp, cappy, name_str, Parrot_str_new_constant(interp, "KnowHOWAttribute")); VTABLE_set_string_keyed_str(interp, cappy, repr_str, Parrot_str_new_constant(interp, "P6str")); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); cappy = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); knowhow_attr = VTABLE_get_pmc_keyed_int(interp, cappy, 0); how = STABLE(knowhow_attr)->HOW; /* Add new method. */ meth = STABLE(how)->find_method(interp, how, Parrot_str_new_constant(interp, "add_method"), NO_HINT); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, how); VTABLE_push_pmc(interp, cappy, knowhow_attr); VTABLE_push_string(interp, cappy, Parrot_str_new_constant(interp, "new")); VTABLE_push_pmc(interp, cappy, wrap_c(interp, F2DPTR(attr_new))); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); /* Add name method. */ cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, how); VTABLE_push_pmc(interp, cappy, knowhow_attr); VTABLE_push_string(interp, cappy, name_str); VTABLE_push_pmc(interp, cappy, wrap_c(interp, F2DPTR(attr_name))); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); /* Compose. */ meth = STABLE(knowhow)->find_method(interp, how, Parrot_str_new_constant(interp, "compose"), NO_HINT); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, how); VTABLE_push_pmc(interp, cappy, knowhow_attr); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); /* Associate the created object with the intial core serialization * context. */ VTABLE_set_pmc_keyed_int(interp, sc, 2, knowhow_attr); SC_PMC(knowhow_attr) = sc; STABLE(knowhow_attr)->sc = sc; return knowhow_attr; }
static void code_pair_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *obj) { CodePairContData *data = (CodePairContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->store_code, NULL); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &store_arg_callsite); tc->cur_frame->args[0].o = cont; tc->cur_frame->args[1].o = obj; STABLE(code)->invoke(tc, code, &store_arg_callsite, tc->cur_frame->args); }
/* Marks a collectable item (object, type object, STable). */ void MVM_gc_mark_collectable(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMCollectable *new_addr) { MVMuint16 i; MVM_gc_worklist_add(tc, worklist, &new_addr->sc); if (!(new_addr->flags & (MVM_CF_TYPE_OBJECT | MVM_CF_STABLE))) { /* Need to view it as an object in here. */ MVMObject *new_addr_obj = (MVMObject *)new_addr; /* Add the STable to the worklist. */ MVM_gc_worklist_add(tc, worklist, &new_addr_obj->st); /* If needed, mark it. This will add addresses to the worklist * that will need updating. Note that we are passing the address * of the object *after* copying it since those are the addresses * we care about updating; the old chunk of memory is now dead! */ if (MVM_GC_DEBUG_ENABLED(MVM_GC_DEBUG_COLLECT) && !STABLE(new_addr_obj)) MVM_panic(MVM_exitcode_gcnursery, "Found an outdated reference to address %p", new_addr); if (REPR(new_addr_obj)->gc_mark) REPR(new_addr_obj)->gc_mark(tc, STABLE(new_addr_obj), OBJECT_BODY(new_addr_obj), worklist); } else if (new_addr->flags & MVM_CF_TYPE_OBJECT) { /* Add the STable to the worklist. */ MVM_gc_worklist_add(tc, worklist, &((MVMObject *)new_addr)->st); } else if (new_addr->flags & MVM_CF_STABLE) { /* Add all references in the STable to the work list. */ MVMSTable *new_addr_st = (MVMSTable *)new_addr; MVM_gc_worklist_add(tc, worklist, &new_addr_st->HOW); MVM_gc_worklist_add(tc, worklist, &new_addr_st->WHAT); MVM_gc_worklist_add(tc, worklist, &new_addr_st->method_cache); for (i = 0; i < new_addr_st->vtable_length; i++) MVM_gc_worklist_add(tc, worklist, &new_addr_st->vtable[i]); for (i = 0; i < new_addr_st->type_check_cache_length; i++) MVM_gc_worklist_add(tc, worklist, &new_addr_st->type_check_cache[i]); if (new_addr_st->container_spec) if (new_addr_st->container_spec->gc_mark_data) new_addr_st->container_spec->gc_mark_data(tc, new_addr_st, worklist); if (new_addr_st->boolification_spec) MVM_gc_worklist_add(tc, worklist, &new_addr_st->boolification_spec->method); if (new_addr_st->invocation_spec) { MVM_gc_worklist_add(tc, worklist, &new_addr_st->invocation_spec->class_handle); MVM_gc_worklist_add(tc, worklist, &new_addr_st->invocation_spec->attr_name); MVM_gc_worklist_add(tc, worklist, &new_addr_st->invocation_spec->invocation_handler); } MVM_gc_worklist_add(tc, worklist, &new_addr_st->WHO); /* If it needs to have its REPR data marked, do that. */ if (new_addr_st->REPR->gc_mark_repr_data) new_addr_st->REPR->gc_mark_repr_data(tc, new_addr_st, worklist); } else { MVM_panic(MVM_exitcode_gcnursery, "Internal error: impossible case encountered in GC marking"); } }
static void code_pair_fetch(MVMThreadContext *tc, MVMObject *cont, MVMRegister *res) { CodePairContData *data = (CodePairContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->fetch_code); tc->cur_frame->return_value = res; tc->cur_frame->return_type = MVM_RETURN_OBJ; tc->cur_frame->return_address = *(tc->interp_cur_op); tc->cur_frame->args[0].o = cont; STABLE(code)->invoke(tc, code, &fetch_arg_callsite, tc->cur_frame->args); }
/* Bootstraps the KnowHOW type. */ static void bootstrap_KnowHOW(MVMThreadContext *tc) { MVMObject *VMString = tc->instance->VMString; MVMObject *BOOTArray = tc->instance->boot_types->BOOTArray; MVMObject *BOOTHash = tc->instance->boot_types->BOOTHash; /* Create our KnowHOW type object. Note we don't have a HOW just yet, so * pass in NULL. */ MVMREPROps *REPR = MVM_repr_get_by_id(tc, MVM_REPR_ID_KnowHOWREPR); MVMObject *knowhow = REPR->type_object_for(tc, NULL); /* We create a KnowHOW instance that can describe itself. This means * (once we tie the knot) that .HOW.HOW.HOW.HOW etc will always return * that, which closes the model up. Note that the STable for it must * be allocated first, since that holds the allocation size. */ MVMKnowHOWREPR *knowhow_how; MVMSTable *st = MVM_gc_allocate_stable(tc, REPR, NULL); st->WHAT = (MVMObject *)knowhow; st->size = sizeof(MVMKnowHOWREPR); knowhow_how = (MVMKnowHOWREPR *)REPR->allocate(tc, st); st->HOW = (MVMObject *)knowhow_how; knowhow_how->common.st = st; /* Add various methods to the KnowHOW's HOW. */ REPR->initialize(tc, NULL, (MVMObject *)knowhow_how, &knowhow_how->body); add_knowhow_how_method(tc, knowhow_how, "new_type", new_type); add_knowhow_how_method(tc, knowhow_how, "add_method", add_method); add_knowhow_how_method(tc, knowhow_how, "add_attribute", add_attribute); add_knowhow_how_method(tc, knowhow_how, "compose", compose); add_knowhow_how_method(tc, knowhow_how, "attributes", attributes); add_knowhow_how_method(tc, knowhow_how, "methods", methods); add_knowhow_how_method(tc, knowhow_how, "name", name); /* Set name KnowHOW for the KnowHOW's HOW. */ knowhow_how->body.name = MVM_string_ascii_decode_nt(tc, VMString, "KnowHOW"); /* Set this built up HOW as the KnowHOW's HOW. */ STABLE(knowhow)->HOW = (MVMObject *)knowhow_how; /* Give it an authoritative method cache; this in turn will make the * method dispatch bottom out. */ STABLE(knowhow)->method_cache = knowhow_how->body.methods; STABLE(knowhow)->mode_flags = MVM_METHOD_CACHE_AUTHORITATIVE; STABLE(knowhow_how)->method_cache = knowhow_how->body.methods; STABLE(knowhow_how)->mode_flags = MVM_METHOD_CACHE_AUTHORITATIVE; /* Associate the created objects with the initial core serialization * context. */ /* XXX TODO */ /* Stash the created KnowHOW. */ tc->instance->KnowHOW = (MVMObject *)knowhow; MVM_gc_root_add_permanent(tc, (MVMCollectable **)&tc->instance->KnowHOW); }
static void code_pair_store(MVMThreadContext *tc, MVMObject *cont, MVMObject *obj) { CodePairContData *data = (CodePairContData *)STABLE(cont)->container_data; MVMObject *code = MVM_frame_find_invokee(tc, data->store_code); tc->cur_frame->return_value = NULL; tc->cur_frame->return_type = MVM_RETURN_VOID; tc->cur_frame->return_address = *(tc->interp_cur_op); tc->cur_frame->args[0].o = cont; tc->cur_frame->args[1].o = obj; STABLE(code)->invoke(tc, code, &store_arg_callsite, tc->cur_frame->args); }
/* Locates a method by name. Returns the method if it exists, or throws an * exception if it can not be found. */ void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { MVMObject *cache, *HOW, *find_method, *code; if (MVM_is_null(tc, obj)) MVM_exception_throw_adhoc(tc, "Cannot call method '%s' on a null object", MVM_string_utf8_encode_C_string(tc, name)); /* First try to find it in the cache. If we find it, we have a result. * If we don't find it, but the cache is authoritative, then error. */ cache = STABLE(obj)->method_cache; if (cache && IS_CONCRETE(cache)) { MVMObject *meth = MVM_repr_at_key_o(tc, cache, name); if (!MVM_is_null(tc, meth)) { res->o = meth; return; } if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) { MVMObject *handler = MVM_hll_current(tc)->method_not_found_error; if (!MVM_is_null(tc, handler)) { handler = MVM_frame_find_invokee(tc, handler, NULL); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &mnfe_callsite); tc->cur_frame->args[0].o = obj; tc->cur_frame->args[1].s = name; STABLE(handler)->invoke(tc, handler, &mnfe_callsite, tc->cur_frame->args); return; } else { MVM_exception_throw_adhoc(tc, "Cannot find method '%s'", MVM_string_utf8_encode_C_string(tc, name)); } } } /* Otherwise, need to call the find_method method. We make the assumption * that the invocant's meta-object's type is composed. */ HOW = STABLE(obj)->HOW; find_method = MVM_6model_find_method_cache_only(tc, HOW, tc->instance->str_consts.find_method); if (MVM_is_null(tc, find_method)) MVM_exception_throw_adhoc(tc, "Cannot find method '%s': no method cache and no .^find_method", MVM_string_utf8_encode_C_string(tc, name)); /* Set up the call, using the result register as the target. */ code = MVM_frame_find_invokee(tc, find_method, NULL); MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, &fm_callsite); tc->cur_frame->args[0].o = HOW; tc->cur_frame->args[1].o = obj; tc->cur_frame->args[2].s = name; STABLE(code)->invoke(tc, code, &fm_callsite, tc->cur_frame->args); }
/* Composes the meta-object. */ static void compose(PARROT_INTERP, PMC *nci) { PMC * unused; PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0); PMC *obj = VTABLE_get_pmc_keyed_int(interp, capture, 1); STABLE(obj)->method_cache = ((KnowHOWREPRInstance *)PMC_data(self))->body.methods; STABLE(obj)->mode_flags = METHOD_CACHE_AUTHORITATIVE; STABLE(obj)->type_check_cache_length = 1; STABLE(obj)->type_check_cache = (PMC **)mem_sys_allocate(sizeof(PMC *)); STABLE(obj)->type_check_cache[0] = obj; unused = Parrot_pcc_build_call_from_c_args(interp, capture, "P", obj); }
void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { MVMObject *cache, *HOW, *find_method, *code; MVMCallsite *findmeth_callsite; if (MVM_is_null(tc, obj)) MVM_exception_throw_adhoc(tc, "Cannot call method '%s' on a null object", MVM_string_utf8_encode_C_string(tc, name)); /* First try to find it in the cache. If we find it, we have a result. * If we don't find it, but the cache is authoritative, then error. */ cache = get_method_cache(tc, STABLE(obj)); if (cache && IS_CONCRETE(cache)) { MVMObject *meth = MVM_repr_at_key_o(tc, cache, name); if (!MVM_is_null(tc, meth)) { res->o = meth; return; } if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) { die_over_missing_method(tc, obj, name); return; } } /* Otherwise, need to call the find_method method. We make the assumption * that the invocant's meta-object's type is composed. */ HOW = MVM_6model_get_how(tc, STABLE(obj)); find_method = MVM_6model_find_method_cache_only(tc, HOW, tc->instance->str_consts.find_method); if (MVM_is_null(tc, find_method)) MVM_exception_throw_adhoc(tc, "Cannot find method '%s': no method cache and no .^find_method", MVM_string_utf8_encode_C_string(tc, name)); /* Set up the call, using the result register as the target. */ code = MVM_frame_find_invokee(tc, find_method, NULL); findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD); MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite); { FindMethodSRData *fm = MVM_malloc(sizeof(FindMethodSRData)); fm->obj = obj; fm->name = name; fm->res = res; tc->cur_frame->special_return = late_bound_find_method_return; tc->cur_frame->special_return_data = fm; tc->cur_frame->mark_special_return_data = mark_find_method_sr_data; } tc->cur_frame->args[0].o = HOW; tc->cur_frame->args[1].o = obj; tc->cur_frame->args[2].s = name; STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args); }
/* Checks if an object has a given type, using the cache only. */ MVMint64 MVM_6model_istype_cache_only(MVMThreadContext *tc, MVMObject *obj, MVMObject *type) { if (!MVM_is_null(tc, obj)) { MVMuint16 i, elems = STABLE(obj)->type_check_cache_length; MVMObject **cache = STABLE(obj)->type_check_cache; if (cache) for (i = 0; i < elems; i++) { if (cache[i] == type) return 1; } } return 0; }
/* KnowHOW.new_type method. Creates a new type with this HOW as its meta-object. */ static void new_type(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMObject *self, *HOW, *type_object, *BOOTHash, *stash; MVMArgInfo repr_arg, name_arg; MVMString *repr_name, *name; const MVMREPROps *repr_to_use; 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, 1, 1); self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; repr_arg = MVM_args_get_named_str(tc, &arg_ctx, instance->str_consts.repr, MVM_ARG_OPTIONAL); name_arg = MVM_args_get_named_str(tc, &arg_ctx, instance->str_consts.name, MVM_ARG_OPTIONAL); MVM_args_proc_cleanup(tc, &arg_ctx); if (REPR(self)->ID != MVM_REPR_ID_KnowHOWREPR) MVM_exception_throw_adhoc(tc, "KnowHOW methods must be called on object with REPR KnowHOWREPR"); /* See if we have a representation name; if not default to P6opaque. */ repr_name = repr_arg.exists ? repr_arg.arg.s : instance->str_consts.P6opaque; repr_to_use = MVM_repr_get_by_name(tc, repr_name); MVM_gc_root_temp_push(tc, (MVMCollectable **)&name_arg); /* We first create a new HOW instance. */ HOW = REPR(self)->allocate(tc, STABLE(self)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&HOW); /* Create a new type object of the desired REPR. (Note that we can't * default to KnowHOWREPR here, since it doesn't know how to actually * store attributes, it's just for bootstrapping knowhow's. */ type_object = repr_to_use->type_object_for(tc, HOW); MVM_gc_root_temp_push(tc, (MVMCollectable **)&type_object); /* This may move name_arg.arg.s so do it first: */ REPR(HOW)->initialize(tc, STABLE(HOW), HOW, OBJECT_BODY(HOW)); /* See if we were given a name; put it into the meta-object if so. */ name = name_arg.exists ? name_arg.arg.s : instance->str_consts.anon; MVM_ASSIGN_REF(tc, &(HOW->header), ((MVMKnowHOWREPR *)HOW)->body.name, name); /* Set .WHO to an empty hash. */ BOOTHash = tc->instance->boot_types.BOOTHash; stash = REPR(BOOTHash)->allocate(tc, STABLE(BOOTHash)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&stash); MVM_ASSIGN_REF(tc, &(STABLE(type_object)->header), STABLE(type_object)->WHO, stash); /* Return the type object. */ MVM_args_set_result_obj(tc, type_object, MVM_RETURN_CURRENT_FRAME); MVM_gc_root_temp_pop_n(tc, 4); }
/* Takes a stub object that existed before we had bootstrapped things and * gives it a meta-object. */ static void add_meta_object(MVMThreadContext *tc, MVMObject *type_obj, char *name) { MVMObject *meta_obj; MVMString *name_str; /* Create meta-object. */ meta_obj = MVM_repr_alloc_init(tc, STABLE(tc->instance->KnowHOW)->HOW); MVMROOT(tc, meta_obj, { /* Put it in place. */ MVM_ASSIGN_REF(tc, STABLE(type_obj), STABLE(type_obj)->HOW, meta_obj); /* Set name. */ name_str = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, name); MVM_ASSIGN_REF(tc, meta_obj, ((MVMKnowHOWREPR *)meta_obj)->body.name, name_str); });
/* Gets the current value for an attribute. */ static PMC * get_attribute_boxed(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint) { CStructREPRData *repr_data = (CStructREPRData *)st->REPR_data; CStructBody *body = (CStructBody *)data; INTVAL slot; /* Look up slot, then offset and compute address. */ slot = hint >= 0 ? hint : try_get_slot(interp, repr_data, class_handle, name); if (slot >= 0) { INTVAL type = repr_data->attribute_locations[slot] & CSTRUCT_ATTR_MASK; INTVAL real_slot = repr_data->attribute_locations[slot] >> CSTRUCT_ATTR_SHIFT; if(type == CSTRUCT_ATTR_IN_STRUCT) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "CStruct Can't perform boxed get on flattened attributes yet"); else { PMC *obj = body->child_objs[real_slot]; PMC *typeobj = repr_data->member_types[slot]; if(!obj) { void *cobj = get_ptr_at_offset(body->cstruct, repr_data->struct_offsets[slot]); if(cobj) { if(type == CSTRUCT_ATTR_CARRAY) { obj = make_carray_result(interp, typeobj, cobj); } else if(type == CSTRUCT_ATTR_CSTRUCT) { obj = make_cstruct_result(interp, typeobj, cobj); } else if(type == CSTRUCT_ATTR_CPTR) { obj = make_cpointer_result(interp, typeobj, cobj); } else if(type == CSTRUCT_ATTR_STRING) { char *cstr = (char *) cobj; STRING *str = Parrot_str_new_init(interp, cstr, strlen(cstr), Parrot_utf8_encoding_ptr, 0); obj = REPR(typeobj)->allocate(interp, STABLE(typeobj)); REPR(obj)->initialize(interp, STABLE(obj), OBJECT_BODY(obj)); REPR(obj)->box_funcs->set_str(interp, STABLE(obj), OBJECT_BODY(obj), str); PARROT_GC_WRITE_BARRIER(interp, obj); } body->child_objs[real_slot] = obj; } else { obj = typeobj; } } return obj; } }
MVMObject * Kiji_bootstrap_Pair(MVMCompUnit* cu, MVMThreadContext*tc) { MVMObject * type = MVM_6model_find_method( tc, STABLE(tc->instance->KnowHOW)->HOW, MVM_string_ascii_decode_nt(tc, tc->instance->VMString, (char*)"new_type") ); MVMObject * how = STABLE(type)->HOW; CLASS_INIT(); /* CLASS_ADD_METHOD("elems", Hash_elems); */ CLASS_REGISTER(type); return type; }
/* Gets the current value for an attribute. */ static PMC * get_attribute_boxed(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint) { P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data; INTVAL slot; /* Try the slot allocation first. */ slot = hint >= 0 && !(repr_data->mi) ? hint : try_get_slot(interp, repr_data, class_handle, name); if (slot >= 0) { if (!repr_data->flattened_stables[slot]) { PMC *result = get_pmc_at_offset(data, repr_data->attribute_offsets[slot]); if (result) { return result; } else { /* Maybe we know how to auto-viv it to a container. */ if (repr_data->auto_viv_values) { PMC *value = repr_data->auto_viv_values[slot]; if (value != NULL) { if (IS_CONCRETE(value)) { PMC *cloned = REPR(value)->allocate(interp, STABLE(value)); REPR(value)->copy_to(interp, STABLE(value), OBJECT_BODY(value), OBJECT_BODY(cloned)); PARROT_GC_WRITE_BARRIER(interp, cloned); set_pmc_at_offset(data, repr_data->attribute_offsets[slot], cloned); return cloned; } else { set_pmc_at_offset(data, repr_data->attribute_offsets[slot], value); return value; } } } return PMCNULL; } } else { /* Need to produce a boxed version of this attribute. */ STable *st = repr_data->flattened_stables[slot]; PMC *result = st->REPR->allocate(interp, st); st->REPR->copy_to(interp, st, (char *)data + repr_data->attribute_offsets[slot], OBJECT_BODY(result)); PARROT_GC_WRITE_BARRIER(interp, result); return result; } } /* Otherwise, complain that the attribute doesn't exist. */ no_such_attribute(interp, "get", class_handle, name); }
/* Helper for finding a slot number. */ static INTVAL try_get_slot(PARROT_INTERP, P6opaqueREPRData *repr_data, PMC *class_key, STRING *name) { INTVAL slot = -1; if (repr_data->name_to_index_mapping) { P6opaqueNameMap *cur_map_entry = repr_data->name_to_index_mapping; while (cur_map_entry->class_key != NULL) { if (cur_map_entry->class_key == class_key) { if (!PMC_IS_NULL(cur_map_entry->name_map)) { PMC *slot_pmc = VTABLE_get_pmc_keyed_str(interp, cur_map_entry->name_map, name); if (!PMC_IS_NULL(slot_pmc)) slot = VTABLE_get_integer(interp, slot_pmc); break; } else { Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "Null attribute map for P6opaque in class '%Ss'", VTABLE_get_string(interp, introspection_call(interp, class_key, STABLE(class_key)->HOW, Parrot_str_new_constant(interp, "name"), 0))); } } cur_map_entry++; } } return slot; }
/* Attribute name introspection. */ static void attr_name(PARROT_INTERP, PMC *nci) { PMC * unused; PMC *capture = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); PMC *self = VTABLE_get_pmc_keyed_int(interp, capture, 0); STRING *name = REPR(self)->box_funcs->get_str(interp, STABLE(self), OBJECT_BODY(self)); unused = Parrot_pcc_build_call_from_c_args(interp, capture, "S", name); }
MVMint32 MVM_6model_find_method_spesh(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMint32 ss_idx, MVMRegister *res) { /* Missed mono-morph; try cache-only lookup. */ MVMObject *meth = MVM_6model_find_method_cache_only(tc, obj, name); if (!MVM_is_null(tc, meth)) { /* Got it; cache. Must be careful due to threads * reading, races, etc. */ MVMStaticFrame *sf = tc->cur_frame->static_info; uv_mutex_lock(&tc->instance->mutex_spesh_install); if (!tc->cur_frame->effective_spesh_slots[ss_idx + 1]) { MVM_ASSIGN_REF(tc, &(sf->common.header), tc->cur_frame->effective_spesh_slots[ss_idx + 1], (MVMCollectable *)meth); MVM_barrier(); MVM_ASSIGN_REF(tc, &(sf->common.header), tc->cur_frame->effective_spesh_slots[ss_idx], (MVMCollectable *)STABLE(obj)); } uv_mutex_unlock(&tc->instance->mutex_spesh_install); res->o = meth; return 0; } else { /* Fully late-bound. */ MVM_6model_find_method(tc, obj, name, res); return 1; } }
/* Creates a Perl 6 Hash. */ static PMC * Rakudo_binding_create_hash(PARROT_INTERP, PMC *storage) { PMC *type = Rakudo_types_hash_get(); PMC *hash = REPR(type)->allocate(interp, STABLE(type)); VTABLE_set_attr_keyed(interp, hash, Rakudo_types_enummap_get(), STORAGE_str, storage); return hash; }
static STRING *get_str(PARROT_INTERP, STable *st, void *data) { CStrBody *body = (CStrBody *) data; PMC *old_ctx, *cappy, *meth, *enc_pmc; STRING *enc; STR_VTABLE *encoding; if (!body->cstr) return (STRING *) NULL; /* Look up "encoding" method. */ meth = VTABLE_find_method(interp, st->WHAT, Parrot_str_new_constant(interp, "encoding")); if (PMC_IS_NULL(meth)) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "CStr representation expects an 'encoding' method, specifying the encoding"); old_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, st->WHAT); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); cappy = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); enc_pmc = decontainerize(interp, VTABLE_get_pmc_keyed_int(interp, cappy, 0)); enc = REPR(enc_pmc)->box_funcs->get_str(interp, STABLE(enc_pmc), OBJECT_BODY(enc_pmc)); return new_from_cstring(interp, body->cstr, enc); }