/* Introspects the methods. */ static void methods(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMObject *self, *type_obj, *method_table; MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); 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"); method_table = ((MVMKnowHOWREPR *)self)->body.methods; MVM_args_set_result_obj(tc, method_table, MVM_RETURN_CURRENT_FRAME); }
/* 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); }
void MVM_frame_unwind_to(MVMThreadContext *tc, MVMFrame *frame, MVMuint8 *abs_addr, MVMuint32 rel_addr, MVMObject *return_value) { while (tc->cur_frame != frame) { if (tc->cur_frame->static_info->body.has_exit_handler && !(tc->cur_frame->flags & MVM_FRAME_FLAG_EXIT_HAND_RUN)) { /* We're unwinding a frame with an exit handler. Thus we need to * pause the unwind, run the exit handler, and keep enough info * around in order to finish up the unwind afterwards. */ MVMFrame *caller = tc->cur_frame->caller; MVMHLLConfig *hll = MVM_hll_current(tc); MVMObject *handler; if (!caller) MVM_exception_throw_adhoc(tc, "Entry point frame cannot have an exit handler"); if (tc->cur_frame == tc->thread_entry_frame) MVM_exception_throw_adhoc(tc, "Thread entry point frame cannot have an exit handler"); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &exit_arg_callsite); tc->cur_frame->args[0].o = tc->cur_frame->code_ref; tc->cur_frame->args[1].o = NULL; tc->cur_frame->special_return = continue_unwind; { MVMUnwindData *ud = malloc(sizeof(MVMUnwindData)); ud->frame = frame; ud->abs_addr = abs_addr; ud->rel_addr = rel_addr; if (return_value) MVM_exception_throw_adhoc(tc, "return_value + exit_handler case NYI"); tc->cur_frame->special_return_data = ud; } tc->cur_frame->flags |= MVM_FRAME_FLAG_EXIT_HAND_RUN; handler = MVM_frame_find_invokee(tc, hll->exit_handler, NULL); STABLE(handler)->invoke(tc, handler, &exit_arg_callsite, tc->cur_frame->args); return; } else { /* No exit handler, so just remove the frame. */ if (!remove_one_frame(tc, 1)) MVM_panic(1, "Internal error: Unwound entire stack and missed handler"); } } if (abs_addr) *tc->interp_cur_op = abs_addr; else if (rel_addr) *tc->interp_cur_op = *tc->interp_bytecode_start + rel_addr; if (return_value) MVM_args_set_result_obj(tc, return_value, 1); }
/* 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); }
/* Adds an method. */ static void add_attribute(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMObject *self, *attr, *attributes; /* 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, 3, 3); self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; attr = MVM_args_get_pos_obj(tc, &arg_ctx, 2, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); /* Ensure we have the required representations. */ 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"); if (REPR(attr)->ID != MVM_REPR_ID_KnowHOWAttributeREPR) MVM_exception_throw_adhoc(tc, "KnowHOW attributes must use KnowHOWAttributeREPR"); /* Add to method table. */ attributes = ((MVMKnowHOWREPR *)self)->body.attributes; MVM_repr_push_o(tc, attributes, attr); /* Return added attribute as result. */ MVM_args_set_result_obj(tc, attr, MVM_RETURN_CURRENT_FRAME); }
/* 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; MVMint64 num_attrs, i; /* Get arguments. */ MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); 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), 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 = malloc(sizeof(MVMObject *)); MVM_ASSIGN_REF(tc, STABLE(type_obj), STABLE(type_obj)->type_check_cache[0], type_obj); /* Next steps will allocate, so make sure we keep hold of the type * object and ourself. */ MVM_gc_root_temp_push(tc, (MVMCollectable **)&self); 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 = tc->instance->boot_types->BOOTArray; BOOTHash = tc->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); REPR(repr_info)->initialize(tc, STABLE(repr_info), repr_info, OBJECT_BODY(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); REPR(type_info)->initialize(tc, STABLE(type_info), type_info, OBJECT_BODY(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); REPR(attr_info_list)->initialize(tc, STABLE(attr_info_list), attr_info_list, OBJECT_BODY(attr_info_list)); MVM_repr_push_o(tc, type_info, attr_info_list); attributes = ((MVMKnowHOWREPR *)self)->body.attributes; MVM_gc_root_temp_push(tc, (MVMCollectable **)&attributes); 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); MVM_gc_root_temp_push(tc, (MVMCollectable **)&attr_info); MVM_gc_root_temp_push(tc, (MVMCollectable **)&attribute); if (REPR((MVMObject *)attribute)->ID != MVM_REPR_ID_KnowHOWAttributeREPR) MVM_exception_throw_adhoc(tc, "KnowHOW attributes must use KnowHOWAttributeREPR"); REPR(attr_info)->initialize(tc, STABLE(attr_info), attr_info, OBJECT_BODY(attr_info)); REPR(attr_info)->ass_funcs->bind_key_boxed(tc, STABLE(attr_info), attr_info, OBJECT_BODY(attr_info), (MVMObject *)str_name, (MVMObject *)attribute->body.name); REPR(attr_info)->ass_funcs->bind_key_boxed(tc, STABLE(attr_info), attr_info, OBJECT_BODY(attr_info), (MVMObject *)str_type, attribute->body.type); if (attribute->body.box_target) { /* Merely having the key serves as a "yes". */ REPR(attr_info)->ass_funcs->bind_key_boxed(tc, STABLE(attr_info), attr_info, OBJECT_BODY(attr_info), (MVMObject *)str_box_target, attr_info); } MVM_repr_push_o(tc, attr_info_list, attr_info); MVM_gc_root_temp_pop_n(tc, 2); } /* ...followed by a list of parents (none). */ parent_info = REPR(BOOTArray)->allocate(tc, STABLE(BOOTArray)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&parent_info); REPR(parent_info)->initialize(tc, STABLE(parent_info), parent_info, OBJECT_BODY(parent_info)); MVM_repr_push_o(tc, type_info, parent_info); /* Finally, this all goes in a hash under the key 'attribute'. */ repr_info_hash = REPR(BOOTHash)->allocate(tc, STABLE(BOOTHash)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&repr_info_hash); REPR(repr_info_hash)->initialize(tc, STABLE(repr_info_hash), repr_info_hash, OBJECT_BODY(repr_info_hash)); REPR(repr_info_hash)->ass_funcs->bind_key_boxed(tc, STABLE(repr_info_hash), repr_info_hash, OBJECT_BODY(repr_info_hash), (MVMObject *)str_attribute, repr_info); /* Compose the representation using it. */ REPR(type_obj)->compose(tc, STABLE(type_obj), repr_info_hash); /* Clear temporary roots. */ MVM_gc_root_temp_pop_n(tc, 10); /* Return type object. */ MVM_args_set_result_obj(tc, type_obj, MVM_RETURN_CURRENT_FRAME); }