/* 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); }
static void Str_say(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); MVMObject* self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); MVM_gc_root_temp_push(tc, (MVMCollectable **)&self); MVMString * self_s = REPR(self)->box_funcs->get_str(tc, STABLE(self), self, OBJECT_BODY(self)); MVM_string_say(tc, self_s); MVM_gc_root_temp_pop_n(tc, 1); }
/* 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); }
static void File_eof(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); MVMObject* self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); MVM_gc_root_temp_push(tc, (MVMCollectable **)&self); MVMint64 result = MVM_file_eof(tc, self); MVM_args_set_result_int(tc, result, MVM_RETURN_CURRENT_FRAME); MVM_gc_root_temp_pop_n(tc, 1); }
static void Str_length(MVMThreadContext *tc, MVMCallsite *callsite, MVMRegister *args) { MVMArgProcContext arg_ctx; arg_ctx.named_used = NULL; MVM_args_proc_init(tc, &arg_ctx, callsite, args); MVMObject* self = MVM_args_get_pos_obj(tc, &arg_ctx, 0, MVM_ARG_REQUIRED).arg.o; MVM_args_proc_cleanup(tc, &arg_ctx); MVM_gc_root_temp_push(tc, (MVMCollectable **)&self); MVMString * self_s = REPR(self)->box_funcs->get_str(tc, STABLE(self), self, OBJECT_BODY(self)); MVMint64 length = NUM_GRAPHS((MVMString*)self_s); MVM_args_set_result_int(tc, length, MVM_RETURN_CURRENT_FRAME); MVM_gc_root_temp_pop_n(tc, 1); }
MVMObject * MVM_args_save_capture(MVMThreadContext *tc, MVMFrame *frame) { MVMObject *cc_obj; MVMROOT(tc, frame, { MVMCallCapture *cc = (MVMCallCapture *) (cc_obj = MVM_repr_alloc_init(tc, tc->instance->CallCapture)); /* Copy the arguments. */ MVMuint32 arg_size = frame->params.arg_count * sizeof(MVMRegister); MVMRegister *args = MVM_malloc(arg_size); memcpy(args, frame->params.args, arg_size); /* Set up the call capture, copying the callsite. */ cc->body.apc = (MVMArgProcContext *)MVM_calloc(1, sizeof(MVMArgProcContext)); MVM_args_proc_init(tc, cc->body.apc, MVM_args_copy_uninterned_callsite(tc, &frame->params), args); });
/* 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; 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); }); });
/* Takes a static frame and a thread context. Invokes the static frame. */ void MVM_frame_invoke(MVMThreadContext *tc, MVMStaticFrame *static_frame, MVMCallsite *callsite, MVMRegister *args, MVMFrame *outer, MVMObject *code_ref) { MVMFrame *frame; MVMuint32 pool_index; MVMFrame *node; int fresh = 0; MVMStaticFrameBody *static_frame_body = &static_frame->body; /* If the frame was never invoked before, need initial calculations * and verification. */ if (!static_frame_body->invoked) prepare_and_verify_static_frame(tc, static_frame); pool_index = static_frame_body->pool_index; node = tc->frame_pool_table[pool_index]; if (node == NULL) { fresh = 1; frame = malloc(sizeof(MVMFrame)); frame->params.named_used = NULL; /* Ensure special return pointer is null. */ frame->special_return = NULL; } else { tc->frame_pool_table[pool_index] = node->outer; node->outer = NULL; frame = node; } /* Copy thread context (back?) into the frame. */ frame->tc = tc; /* Set static frame. */ frame->static_info = static_frame; /* Store the code ref (NULL at the top-level). */ frame->code_ref = code_ref; /* Allocate space for lexicals and work area, copying the default lexical * environment into place. */ if (static_frame_body->env_size) { if (fresh) frame->env = malloc(static_frame_body->env_size); memcpy(frame->env, static_frame_body->static_env, static_frame_body->env_size); } else { frame->env = NULL; } if (static_frame_body->work_size) { if (fresh) frame->work = malloc(static_frame_body->work_size); memset(frame->work, 0, static_frame_body->work_size); } else { frame->work = NULL; } /* Calculate args buffer position. */ frame->args = static_frame_body->work_size ? frame->work + static_frame_body->num_locals : NULL; /* Outer. */ if (outer) { /* We were provided with an outer frame; just ensure that it is * based on the correct static frame. */ // if (outer->static_info == static_frame_body->outer) frame->outer = outer; // else // MVM_exception_throw_adhoc(tc, // "Provided outer frame %p (%s %s) does not match expected static frame type %p (%s %s)", // outer->static_info, // MVM_string_utf8_encode_C_string(tc, MVM_repr_get_by_id(tc, REPR(outer->static_info)->ID)->name), // outer->static_info->body.name ? MVM_string_utf8_encode_C_string(tc, outer->static_info->body.name) : "<anonymous static frame>", // static_frame_body->outer, // MVM_string_utf8_encode_C_string(tc, MVM_repr_get_by_id(tc, REPR(static_frame_body->outer)->ID)->name), // static_frame_body->outer->body.name ? MVM_string_utf8_encode_C_string(tc, static_frame_body->outer->body.name) : "<anonymous static frame>"); } else if (static_frame_body->outer) { /* We need an outer, but none was provided by a closure. See if * we can find an appropriate frame on the current call stack. */ MVMFrame *candidate = tc->cur_frame; frame->outer = NULL; while (candidate) { if (candidate->static_info == static_frame_body->outer) { frame->outer = candidate; break; } candidate = candidate->caller; } if (!frame->outer) { frame->outer = static_frame_body->outer->body.prior_invocation; if (!frame->outer) MVM_exception_throw_adhoc(tc, "Cannot locate an outer frame for the call"); } } else { frame->outer = NULL; } if (frame->outer) MVM_frame_inc_ref(tc, frame->outer); /* Caller is current frame in the thread context. */ if (tc->cur_frame) frame->caller = MVM_frame_inc_ref(tc, tc->cur_frame); else frame->caller = NULL; /* Initial reference count is 1 by virtue of it being the currently * executing frame. */ frame->ref_count = 1; frame->gc_seq_number = 0; /* Initialize argument processing. */ MVM_args_proc_init(tc, &frame->params, callsite, args); /* Update interpreter and thread context, so next execution will use this * frame. */ tc->cur_frame = frame; *(tc->interp_cur_op) = static_frame_body->bytecode; *(tc->interp_bytecode_start) = static_frame_body->bytecode; *(tc->interp_reg_base) = frame->work; *(tc->interp_cu) = static_frame_body->cu; }
/* 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); }
/* Takes a static frame and a thread context. Invokes the static frame. */ void MVM_frame_invoke(MVMThreadContext *tc, MVMStaticFrame *static_frame, MVMCallsite *callsite, MVMRegister *args, MVMFrame *outer, MVMObject *code_ref) { MVMFrame *frame; MVMuint32 pool_index, found_spesh; MVMFrame *node; int fresh = 0; MVMStaticFrameBody *static_frame_body = &static_frame->body; /* If the frame was never invoked before, need initial calculations * and verification. */ if (!static_frame_body->invoked) prepare_and_verify_static_frame(tc, static_frame); /* Get frame body from the re-use pool, or allocate it. */ pool_index = static_frame_body->pool_index; if (pool_index >= tc->frame_pool_table_size) grow_frame_pool(tc, pool_index); node = tc->frame_pool_table[pool_index]; if (node == NULL) { fresh = 1; frame = malloc(sizeof(MVMFrame)); frame->params.named_used = NULL; /* Ensure special return pointers and continuation tags are null. */ frame->special_return = NULL; frame->special_unwind = NULL; frame->continuation_tags = NULL; } else { tc->frame_pool_table[pool_index] = node->outer; node->outer = NULL; frame = node; } #if MVM_HLL_PROFILE_CALLS frame->profile_index = tc->profile_index; tc->profile_data[frame->profile_index].duration_nanos = MVM_platform_now(); tc->profile_data[frame->profile_index].callsite_id = 0; /* XXX get a real callsite id */ tc->profile_data[frame->profile_index].code_id = 0; /* XXX get a real code id */ /* increment the profile data index */ ++tc->profile_index; if (tc->profile_index == tc->profile_data_size) { tc->profile_data_size *= 2; tc->profile_data = realloc(tc->profile_data, tc->profile_data_size); } #endif /* Copy thread context (back?) into the frame. */ frame->tc = tc; /* Set static frame. */ frame->static_info = static_frame; /* Store the code ref (NULL at the top-level). */ frame->code_ref = code_ref; /* Allocate space for lexicals and work area, copying the default lexical * environment into place. */ if (static_frame_body->env_size) { if (fresh) frame->env = malloc(static_frame_body->env_size); memcpy(frame->env, static_frame_body->static_env, static_frame_body->env_size); } else { frame->env = NULL; } if (static_frame_body->work_size) { if (fresh || !frame->work) frame->work = malloc(static_frame_body->work_size); memset(frame->work, 0, static_frame_body->work_size); } else { frame->work = NULL; } /* Calculate args buffer position and make sure current call site starts * empty. */ frame->args = static_frame_body->work_size ? frame->work + static_frame_body->num_locals : NULL; frame->cur_args_callsite = NULL; /* Outer. */ if (outer) { /* We were provided with an outer frame; just ensure that it is * based on the correct static frame (compare on bytecode address * to come with nqp::freshcoderef). */ if (outer->static_info->body.bytecode == static_frame_body->outer->body.bytecode) frame->outer = outer; else MVM_exception_throw_adhoc(tc, "When invoking %s, Provided outer frame %p (%s %s) does not match expected static frame type %p (%s %s)", static_frame_body->name ? MVM_string_utf8_encode_C_string(tc, static_frame_body->name) : "<anonymous static frame>", outer->static_info, MVM_repr_get_by_id(tc, REPR(outer->static_info)->ID)->name, outer->static_info->body.name ? MVM_string_utf8_encode_C_string(tc, outer->static_info->body.name) : "<anonymous static frame>", static_frame_body->outer, MVM_repr_get_by_id(tc, REPR(static_frame_body->outer)->ID)->name, static_frame_body->outer->body.name ? MVM_string_utf8_encode_C_string(tc, static_frame_body->outer->body.name) : "<anonymous static frame>"); } else if (static_frame_body->static_code && static_frame_body->static_code->body.outer) { /* We're lacking an outer, but our static code object may have one. * This comes up in the case of cloned protoregexes, for example. */ frame->outer = static_frame_body->static_code->body.outer; } else if (static_frame_body->outer) { /* Auto-close, and cache it in the static frame. */ frame->outer = autoclose(tc, static_frame_body->outer); static_frame_body->static_code->body.outer = MVM_frame_inc_ref(tc, frame->outer); } else { frame->outer = NULL; } if (frame->outer) MVM_frame_inc_ref(tc, frame->outer); /* Caller is current frame in the thread context. */ if (tc->cur_frame) frame->caller = MVM_frame_inc_ref(tc, tc->cur_frame); else frame->caller = NULL; frame->keep_caller = 0; frame->in_continuation = 0; /* Initial reference count is 1 by virtue of it being the currently * executing frame. */ MVM_store(&frame->ref_count, 1); MVM_store(&frame->gc_seq_number, 0); /* Initialize argument processing. */ MVM_args_proc_init(tc, &frame->params, callsite, args); /* Make sure there's no frame context pointer and special return data * won't be marked. */ frame->context_object = NULL; frame->mark_special_return_data = NULL; /* Clear frame flags. */ frame->flags = 0; /* See if any specializations apply. */ found_spesh = 0; if (++static_frame_body->invocations >= 10 && callsite->is_interned) { /* Look for specialized bytecode. */ MVMint32 num_spesh = static_frame_body->num_spesh_candidates; MVMint32 i, j; for (i = 0; i < num_spesh; i++) { MVMSpeshCandidate *cand = &static_frame_body->spesh_candidates[i]; if (cand->cs == callsite) { MVMint32 match = 1; for (j = 0; j < cand->num_guards; j++) { MVMint32 pos = cand->guards[j].slot; MVMSTable *st = (MVMSTable *)cand->guards[j].match; MVMObject *arg = args[pos].o; if (!arg) { match = 0; break; } switch (cand->guards[j].kind) { case MVM_SPESH_GUARD_CONC: if (!IS_CONCRETE(arg) || STABLE(arg) != st) match = 0; break; case MVM_SPESH_GUARD_TYPE: if (IS_CONCRETE(arg) || STABLE(arg) != st) match = 0; break; case MVM_SPESH_GUARD_DC_CONC: { MVMRegister dc; STABLE(arg)->container_spec->fetch(tc, arg, &dc); if (!dc.o || !IS_CONCRETE(dc.o) || STABLE(dc.o) != st) match = 0; break; } case MVM_SPESH_GUARD_DC_TYPE: { MVMRegister dc; STABLE(arg)->container_spec->fetch(tc, arg, &dc); if (!dc.o || IS_CONCRETE(dc.o) || STABLE(dc.o) != st) match = 0; break; } } if (!match) break; } if (match) { frame->effective_bytecode = cand->bytecode; frame->effective_handlers = cand->handlers; frame->effective_spesh_slots = cand->spesh_slots; frame->spesh_cand = cand; found_spesh = 1; break; } } } /* If we didn't find any, and we're below the limit, can generate a * specialization. */ if (!found_spesh && num_spesh < MVM_SPESH_LIMIT && tc->instance->spesh_enabled) { MVMSpeshCandidate *cand = MVM_spesh_candidate_generate(tc, static_frame, callsite, args); if (cand) { frame->effective_bytecode = cand->bytecode; frame->effective_handlers = cand->handlers; frame->effective_spesh_slots = cand->spesh_slots; frame->spesh_cand = cand; found_spesh = 1; } } } if (!found_spesh) { frame->effective_bytecode = static_frame_body->bytecode; frame->effective_handlers = static_frame_body->handlers; frame->spesh_cand = NULL; } /* Update interpreter and thread context, so next execution will use this * frame. */ tc->cur_frame = frame; *(tc->interp_cur_op) = frame->effective_bytecode; *(tc->interp_bytecode_start) = frame->effective_bytecode; *(tc->interp_reg_base) = frame->work; *(tc->interp_cu) = static_frame_body->cu; /* If we need to do so, make clones of things in the lexical environment * that need it. Note that we do this after tc->cur_frame became the * current frame, to make sure these new objects will certainly get * marked if GC is triggered along the way. */ if (static_frame_body->static_env_flags) { /* Drag everything out of static_frame_body before we start, * as GC action may invalidate it. */ MVMuint8 *flags = static_frame_body->static_env_flags; MVMint64 numlex = static_frame_body->num_lexicals; MVMRegister *state = NULL; MVMint64 state_act = 0; /* 0 = none so far, 1 = first time, 2 = later */ MVMint64 i; for (i = 0; i < numlex; i++) { switch (flags[i]) { case 0: break; case 1: frame->env[i].o = MVM_repr_clone(tc, frame->env[i].o); break; case 2: redo_state: switch (state_act) { case 0: if (!frame->code_ref) MVM_exception_throw_adhoc(tc, "Frame must have code-ref to have state variables"); state = ((MVMCode *)frame->code_ref)->body.state_vars; if (state) { /* Already have state vars; pull them from this. */ state_act = 2; } else { /* Allocate storage for state vars. */ state = malloc(frame->static_info->body.env_size); memset(state, 0, frame->static_info->body.env_size); ((MVMCode *)frame->code_ref)->body.state_vars = state; state_act = 1; /* Note that this frame should run state init code. */ frame->flags |= MVM_FRAME_FLAG_STATE_INIT; } goto redo_state; case 1: frame->env[i].o = MVM_repr_clone(tc, frame->env[i].o); MVM_ASSIGN_REF(tc, &(frame->code_ref->header), state[i].o, frame->env[i].o); break; case 2: frame->env[i].o = state[i].o; break; } break; default: MVM_exception_throw_adhoc(tc, "Unknown lexical environment setup flag"); } } } }