Пример #1
0
/* 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);
}
Пример #2
0
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);
}
Пример #3
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);
}
Пример #4
0
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);
}
Пример #5
0
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);
}
Пример #6
0
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);
    });
Пример #7
0
/* 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);
}
Пример #8
0
/* 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);
}
Пример #9
0
/* 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);
            });
        });
Пример #10
0
/* 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;
}
Пример #11
0
/* 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);
}
Пример #12
0
/* 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");
            }
        }
    }
}