Пример #1
0
fix_tedinfo()
    {
    register int ii;

    for (ii = 0; ii < NUM_TI; ii++)
        {
        fix_str(&rs_tedinfo[ii].te_ptext);
        fix_str(&rs_tedinfo[ii].te_ptmplt);
        fix_str(&rs_tedinfo[ii].te_pvalid);
        }
    }
Пример #2
0
fix_frstr()
    {
    register int ii;

    for (ii = 0; ii < NUM_FRSTR; ii++)
        fix_str(&rs_frstr[ii]);
    }
Пример #3
0
fix_objects()
    {
    int test, ii;
    int wchar, hchar;

    graf_handle( &wchar, &hchar, &ii, &ii );

    for (ii = 0; ii < NUM_OBS; ii++)
        {
        rs_object[ii].ob_x = adj(rs_object[ii].ob_x, wchar);
        rs_object[ii].ob_y = adj(rs_object[ii].ob_y, hchar);
        rs_object[ii].ob_width = adj(rs_object[ii].ob_width, wchar);
        rs_object[ii].ob_height = adj(rs_object[ii].ob_height, hchar);
        test = (int) rs_object[ii].ob_spec;

        switch (rs_object[ii].ob_type)
            {
        case G_TITLE:
        case G_STRING:
        case G_BUTTON:
            fix_str(&rs_object[ii].ob_spec);
            break;

        case G_TEXT:
        case G_BOXTEXT:
        case G_FTEXT:
        case G_FBOXTEXT:
            if (test != NIL)
               rs_object[ii].ob_spec =
                (char *) &rs_tedinfo[test];
            break;

#ifdef NOT_NEED
        case G_ICON:
            if (test != NIL)
               rs_object[ii].ob_spec =
                (char *) &rs_iconblk[test];
            break;

        case G_IMAGE:
            if (test != NIL)
               rs_object[ii].ob_spec =
                (char *) &rs_bitblk[test];
            break;
#endif
        default:
            break;
            }
        }
    }
Пример #4
0
bool AVConfig::Init()
{
	int video_device = NULL;
	const char *device_name;
	struct stat st;

	//check if there're essential settings
	if(!getRoot()->exists("audio"))
		getRoot()->add("audio", Setting::TypeGroup);
	if(!getRoot()->exists("video"))
		getRoot()->add("video", Setting::TypeGroup);

	//open video device
	if(!getVideoSettings()->exists("device"))
		getVideoSettings()->add("device", Setting::TypeString) = "/dev/video0";
	device_name = (*getVideoSettings())["device"];
	if(-1 == stat(device_name, &st))
	{
		log_message(1, "AVConfig: Cannot identify '%s': %d, %s.", device_name, errno, strerror (errno));
		return false;
	}
	if(!S_ISCHR(st.st_mode))
	{
		log_message(1, "AVConfig: %s is no device.", device_name);
		return false;
	}

	video_device = open(device_name, O_RDWR | O_NONBLOCK, 0);
	if(-1 == video_device)
	{
		log_message(1, "AVConfig: Cannot open '%s': %d, %s.", device_name, errno, strerror (errno));
		exit (EXIT_FAILURE);
	}


	//determine video device capabilities
	v4l2_capability cap;
	if(-1 == xioctl(video_device, VIDIOC_QUERYCAP, &cap))
	{
		if (EINVAL == errno)
		{
			log_message(1, "AVConfig: %s is no V4L2 device.", device_name);
			exit(1);
		}
		else log_message(1, "AVConfig: VIDIOC_QUERYCAP: %d, %s.", errno, strerror(errno));
	}
	if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
	{
		log_message(1, "AVConfig: %s is no video capture device.", device_name);
		exit(1);
	}
	if(cap.capabilities & V4L2_CAP_READWRITE)
		log_message(0, "AVConfig: %s supports read i/o.", device_name);
	if(cap.capabilities & V4L2_CAP_STREAMING)
		log_message(0, "AVConfig: %s supports streaming i/o.", device_name);


	//enumerate inputs
	vector<v4l2_input> input_list;
	v4l2_input input;
	int current_input;
	CLEAR(input);
	input.index = 0;
	while(-1 != xioctl(video_device, VIDIOC_ENUMINPUT, &input))
	{
		input_list.push_back(input);
		log_message(0, "AVConfig: Input [%d -- %s] is found.", input.index, input.name);
		input.index++;
	}
	if(-1 == xioctl(video_device, VIDIOC_G_INPUT, &current_input))
	{
		log_errno("AVConfig: VIDIOC_G_INPUT");
		exit(1);
	}
	log_message(0, "AVConfig: Currently selected input is: %d -- %s.", current_input, input_list[current_input].name);


	//enumerate standards if applied
	vector<v4l2_standard> standard_list;
	v4l2_standard standard;
	v4l2_std_id current_standard;
	CLEAR(standard);
	standard.index = 0;
	if(-1 != xioctl(video_device, VIDIOC_G_STD, &current_standard))
	{
        while(0 == xioctl(video_device, VIDIOC_ENUMSTD, &standard))
        {
            if(standard.id & input_list[current_input].std)
            {
                standard_list.push_back(standard);
                log_message(0, "AVConfig: Standard %s is supported by current input.", standard.name);
                log_message(0, "AVConfig: The framerate defined by this standard is: %d", standard.frameperiod.denominator/standard.frameperiod.numerator);
                if(standard.id == current_standard)
                    log_message(0, "AVConfig: Standard %s is currently selected on input.", standard.name);
            }
            standard.index++;
        }
        if(errno != EINVAL || standard.index == 0)
        {
            log_errno("AVConfig: VIDIOC_ENUMSTD");
            return false;
        }
	}

	//enumerate controls
	vector<v4l2_queryctrl> queryctrl_list;
	vector<v4l2_control> control_list;
	map<unsigned long, vector<v4l2_querymenu> > querymenu_list;
	v4l2_queryctrl queryctrl;
	v4l2_control control;
	CLEAR(queryctrl);
	CLEAR(control);
	log_message(0, "AVConfig: Quering standard controls");
	queryctrl.id = V4L2_CID_BASE;
	while(queryctrl.id < V4L2_CID_LASTP1)
	{
	    queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
	    control.id    = queryctrl.id;
	    int res = query_control(video_device, &queryctrl, &control,
	                            queryctrl_list, control_list, querymenu_list);
        if(-1 == res)
        {
            log_errno("AVConfig: unable to query device control");
            return false;
        }
        else if(0 == res) break;
	}
	log_message(0, "AVConfig: Quering driver specific controls");
	queryctrl.id = V4L2_CID_PRIVATE_BASE;
    while(true)
    {
        queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
        control.id    = queryctrl.id;
        int res = query_control(video_device, &queryctrl, &control,
                                queryctrl_list, control_list, querymenu_list);
        if(-1 == res)
        {
            log_errno("AVConfig: unable to query device control");
            return false;
        }
        else if(0 == res) break;
    }

	//close the device
	close(video_device);

	//construct inputs setting
	Setting *video = getVideoSettings();

	try{ video->remove("input"); } catch(...){}
	video->add("input", Setting::TypeInt) = current_input;

	try{ video->remove("inputs"); } catch(...){}
	Setting &inputs = video->add("inputs", Setting::TypeGroup);
	for(int i = 0; i < input_list.size(); i++)
		inputs.add(fix_str(input_list[i].name), Setting::TypeInt) = i;

    //construct standarts setting
	try{ video->remove("standard"); } catch(...){}
	try{ video->remove("standards"); } catch(...){}
	if(!standard_list.empty())
	{
	    video->add("standard", Setting::TypeInt64) = (long long)current_standard;
        Setting &standards = video->add("standards", Setting::TypeGroup);
        for(int i = 0; i < standard_list.size(); i++)
            standards.add(fix_str(standard_list[i].name), Setting::TypeInt64) = (long long)standard_list[i].id;
	}

	//construct controls setting
	try{ video->remove("controls"); } catch(...){}
	Setting &controls = video->add("controls", Setting::TypeGroup);

	for(int i = 0; i < queryctrl_list.size(); i++)
	{
		Setting &control = controls.add(fix_str(queryctrl_list[i].name), Setting::TypeGroup);
		control.add("id", Setting::TypeInt) = (int)queryctrl_list[i].id;
		control.add("value", Setting::TypeInt) = (int)control_list[i].value;
		control.add("default_value", Setting::TypeInt) = (int)queryctrl_list[i].default_value;
		if(queryctrl_list[i].type == V4L2_CTRL_TYPE_MENU)
		{
			vector<v4l2_querymenu> items = querymenu_list[(int)queryctrl_list[i].id];
			for(int j = 0; j < items.size(); j++)
				control.add(fix_str(items[j].name), Setting::TypeInt64) = (long long)items[j].index;
		}
		else
		{
			control.add("minimum", Setting::TypeInt) = (int)queryctrl_list[i].minimum;
			control.add("maximum", Setting::TypeInt) = (int)queryctrl_list[i].maximum;
			control.add("step", Setting::TypeInt) = (int)queryctrl_list[i].step;
		}
	}

	return true;
}
Пример #5
0
/* Merges the inlinee's spesh graph into the inliner. */
static void merge_graph(MVMThreadContext *tc, MVMSpeshGraph *inliner,
                 MVMSpeshGraph *inlinee, MVMCode *inlinee_code,
                 MVMSpeshIns *invoke_ins) {
    MVMSpeshFacts **merged_facts;
    MVMuint16      *merged_fact_counts;
    MVMint32        i, total_inlines, orig_deopt_addrs;
    MVMSpeshBB     *inlinee_first_bb = NULL, *inlinee_last_bb = NULL;
    MVMint32        active_handlers_at_invoke = 0;

    /* If the inliner and inlinee are from different compilation units, we
     * potentially have to fix up extra things. */
    MVMint32 same_comp_unit = inliner->sf->body.cu == inlinee->sf->body.cu;

    /* Renumber the locals, lexicals, and basic blocks of the inlinee; also
     * re-write any indexes in annotations that need it. */
    MVMSpeshBB *bb = inlinee->entry;
    while (bb) {
        MVMSpeshIns *ins = bb->first_ins;
        while (ins) {
            MVMuint16    opcode = ins->info->opcode;
            MVMSpeshAnn *ann    = ins->annotations;
            while (ann) {
                switch (ann->type) {
                case MVM_SPESH_ANN_FH_START:
                case MVM_SPESH_ANN_FH_END:
                case MVM_SPESH_ANN_FH_GOTO:
                    ann->data.frame_handler_index += inliner->num_handlers;
                    break;
                case MVM_SPESH_ANN_DEOPT_INLINE:
                    ann->data.deopt_idx += inliner->num_deopt_addrs;
                    break;
                case MVM_SPESH_ANN_INLINE_START:
                case MVM_SPESH_ANN_INLINE_END:
                    ann->data.inline_idx += inliner->num_inlines;
                    break;
                }
                ann = ann->next;
            }

            if (opcode == MVM_SSA_PHI) {
                for (i = 0; i < ins->info->num_operands; i++)
                    ins->operands[i].reg.orig += inliner->num_locals;
            }
            else {
                for (i = 0; i < ins->info->num_operands; i++) {
                    MVMuint8 flags = ins->info->operands[i];
                    switch (flags & MVM_operand_rw_mask) {
                    case MVM_operand_read_reg:
                    case MVM_operand_write_reg:
                        ins->operands[i].reg.orig += inliner->num_locals;
                        break;
                    case MVM_operand_read_lex:
                    case MVM_operand_write_lex:
                        ins->operands[i].lex.idx += inliner->num_lexicals;
                        break;
                    default: {
                        MVMuint32 type = flags & MVM_operand_type_mask;
                        if (type == MVM_operand_spesh_slot) {
                            ins->operands[i].lit_i16 += inliner->num_spesh_slots;
                        }
                        else if (type == MVM_operand_callsite) {
                            if (!same_comp_unit)
                                fix_callsite(tc, inliner, inlinee, &(ins->operands[i]));
                        }
                        else if (type == MVM_operand_coderef) {
                            if (!same_comp_unit)
                                fix_coderef(tc, inliner, inlinee, &(ins->operands[i]));
                        }
                        else if (type == MVM_operand_str) {
                            if (!same_comp_unit)
                                fix_str(tc, inliner, inlinee, &(ins->operands[i]));
                        }
                        break;
                        }
                    }
                }
            }

            ins = ins->next;
        }
        bb->idx += inliner->num_bbs - 1; /* -1 as we won't include entry */
        bb->inlined = 1;
        if (!bb->linear_next)
            inlinee_last_bb = bb;
        bb = bb->linear_next;
    }

    /* Incorporate the basic blocks by concatening them onto the end of the
     * linear_next chain of the inliner; skip the inlinee's fake entry BB. */
    bb = inliner->entry;
    while (bb) {
        if (!bb->linear_next) {
            /* Found the end; insert and we're done. */
            bb->linear_next = inlinee_first_bb = inlinee->entry->linear_next;
            bb = NULL;
        }
        else {
            bb = bb->linear_next;
        }
    }

    /* Merge facts. */
    merged_facts = MVM_spesh_alloc(tc, inliner,
        (inliner->num_locals + inlinee->num_locals) * sizeof(MVMSpeshFacts *));
    memcpy(merged_facts, inliner->facts,
        inliner->num_locals * sizeof(MVMSpeshFacts *));
    memcpy(merged_facts + inliner->num_locals, inlinee->facts,
        inlinee->num_locals * sizeof(MVMSpeshFacts *));
    inliner->facts = merged_facts;
    merged_fact_counts = MVM_spesh_alloc(tc, inliner,
        (inliner->num_locals + inlinee->num_locals) * sizeof(MVMuint16));
    memcpy(merged_fact_counts, inliner->fact_counts,
        inliner->num_locals * sizeof(MVMuint16));
    memcpy(merged_fact_counts + inliner->num_locals, inlinee->fact_counts,
        inlinee->num_locals * sizeof(MVMuint16));
    inliner->fact_counts = merged_fact_counts;

    /* Copy over spesh slots. */
    for (i = 0; i < inlinee->num_spesh_slots; i++)
        MVM_spesh_add_spesh_slot(tc, inliner, inlinee->spesh_slots[i]);

    /* If they are from separate compilation units, make another pass through
     * to fix up on wvals. Note we can't do this in the first pass as we must
     * not modify the spesh slots once we've got started with the rewrites.
     * Now we've resolved all that, we're good to map wvals elsewhere into
     * some extra spesh slots. */
    if (!same_comp_unit) {
        bb = inlinee->entry;
        while (bb) {
            MVMSpeshIns *ins = bb->first_ins;
            while (ins) {
                MVMuint16 opcode = ins->info->opcode;
                if (opcode == MVM_OP_wval || opcode == MVM_OP_wval_wide)
                    fix_wval(tc, inliner, inlinee, ins);
                ins = ins->next;
            }
            bb = bb->linear_next;
        }
    }

    /* Merge de-opt tables, if needed. */
    orig_deopt_addrs = inliner->num_deopt_addrs;
    if (inlinee->num_deopt_addrs) {
        assert(inlinee->deopt_addrs != inliner->deopt_addrs);
        inliner->alloc_deopt_addrs += inlinee->alloc_deopt_addrs;
        if (inliner->deopt_addrs)
            inliner->deopt_addrs = MVM_realloc(inliner->deopt_addrs,
                inliner->alloc_deopt_addrs * sizeof(MVMint32) * 2);
        else
            inliner->deopt_addrs = MVM_malloc(inliner->alloc_deopt_addrs * sizeof(MVMint32) * 2);
        memcpy(inliner->deopt_addrs + inliner->num_deopt_addrs * 2,
            inlinee->deopt_addrs, inlinee->alloc_deopt_addrs * sizeof(MVMint32) * 2);
        inliner->num_deopt_addrs += inlinee->num_deopt_addrs;
    }

    /* Merge inlines table, and add us an entry too. */
    total_inlines = inliner->num_inlines + inlinee->num_inlines + 1;
    inliner->inlines = inliner->num_inlines
        ? MVM_realloc(inliner->inlines, total_inlines * sizeof(MVMSpeshInline))
        : MVM_malloc(total_inlines * sizeof(MVMSpeshInline));
    memcpy(inliner->inlines + inliner->num_inlines, inlinee->inlines,
        inlinee->num_inlines * sizeof(MVMSpeshInline));
    for (i = inliner->num_inlines; i < total_inlines - 1; i++) {
        inliner->inlines[i].locals_start += inliner->num_locals;
        inliner->inlines[i].lexicals_start += inliner->num_lexicals;
        inliner->inlines[i].return_deopt_idx += orig_deopt_addrs;
    }
    inliner->inlines[total_inlines - 1].code           = inlinee_code;
    inliner->inlines[total_inlines - 1].g              = inlinee;
    inliner->inlines[total_inlines - 1].locals_start   = inliner->num_locals;
    inliner->inlines[total_inlines - 1].lexicals_start = inliner->num_lexicals;
    switch (invoke_ins->info->opcode) {
    case MVM_OP_invoke_v:
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_VOID;
        break;
    case MVM_OP_invoke_o:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_OBJ;
        break;
    case MVM_OP_invoke_i:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_INT;
        break;
    case MVM_OP_invoke_n:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_NUM;
        break;
    case MVM_OP_invoke_s:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_STR;
        break;
    default:
        MVM_oops(tc, "Spesh inline: unknown invoke instruction");
    }
    inliner->inlines[total_inlines - 1].return_deopt_idx = return_deopt_idx(tc, invoke_ins);
    inliner->num_inlines = total_inlines;

    /* Create/update per-specialization local and lexical type maps. */
    if (!inliner->local_types) {
        MVMint32 local_types_size = inliner->num_locals * sizeof(MVMuint16);
        inliner->local_types = MVM_malloc(local_types_size);
        memcpy(inliner->local_types, inliner->sf->body.local_types, local_types_size);
    }
    inliner->local_types = MVM_realloc(inliner->local_types,
        (inliner->num_locals + inlinee->num_locals) * sizeof(MVMuint16));
    memcpy(inliner->local_types + inliner->num_locals,
        inlinee->local_types ? inlinee->local_types : inlinee->sf->body.local_types,
        inlinee->num_locals * sizeof(MVMuint16));
    if (!inliner->lexical_types) {
        MVMint32 lexical_types_size = inliner->num_lexicals * sizeof(MVMuint16);
        inliner->lexical_types = MVM_malloc(lexical_types_size);
        memcpy(inliner->lexical_types, inliner->sf->body.lexical_types, lexical_types_size);
    }
    inliner->lexical_types = MVM_realloc(inliner->lexical_types,
        (inliner->num_lexicals + inlinee->num_lexicals) * sizeof(MVMuint16));
    memcpy(inliner->lexical_types + inliner->num_lexicals,
        inlinee->lexical_types ? inlinee->lexical_types : inlinee->sf->body.lexical_types,
        inlinee->num_lexicals * sizeof(MVMuint16));

    /* Merge handlers from inlinee. */
    if (inlinee->num_handlers) {
        MVMuint32 total_handlers = inliner->num_handlers + inlinee->num_handlers;
        resize_handlers_table(tc, inliner, total_handlers);
        memcpy(inliner->handlers + inliner->num_handlers, inlinee->handlers,
            inlinee->num_handlers * sizeof(MVMFrameHandler));
        for (i = inliner->num_handlers; i < total_handlers; i++) {
            inliner->handlers[i].block_reg += inliner->num_locals;
            inliner->handlers[i].label_reg += inliner->num_locals;
        }
    }

    /* If the inliner has handlers in effect at the point of the call that we
     * are inlining, then we duplicate those and place them surrounding the
     * inlinee, but with the goto still pointing to the original location.
     * This means that we can still do a linear scan when searching for an
     * exception handler, and don't have to try the (costly and fiddly) matter
     * of trying to traverse the post-inlined call chain. */
    if (inliner->sf->body.num_handlers) {
        /* Walk inliner looking for handlers in effect at the point we hit the
         * invoke instruction we're currently inlining; also record all of the
         * instructions where the handler "goto" annotation lives. */
        MVMuint32 orig_handlers = inliner->sf->body.num_handlers;
        MVMuint8 *active = MVM_spesh_alloc(tc, inliner, orig_handlers);
        MVMSpeshIns **handler_goto_ins = MVM_spesh_alloc(tc, inliner,
            orig_handlers * sizeof(MVMSpeshIns *));
        MVMint32 found_invoke = 0;
        bb = inliner->entry;
        while (bb && !bb->inlined) {
            MVMSpeshIns *ins = bb->first_ins;
            while (ins) {
                MVMSpeshAnn *ann = ins->annotations;
                while (ann) {
                    if (ann->type == MVM_SPESH_ANN_FH_GOTO) {
                        if (ann->data.frame_handler_index < orig_handlers)
                            handler_goto_ins[ann->data.frame_handler_index] = ins;
                    }
                    else if (!found_invoke) {
                        /* Only update these to the point we found the invoke
                         * being inlined, so it serves as a snapshot of what
                         * is active. */
                        if (ann->type == MVM_SPESH_ANN_FH_START)
                            active[ann->data.frame_handler_index] = 1;
                        else if (ann->type == MVM_SPESH_ANN_FH_END)
                            active[ann->data.frame_handler_index] = 0;
                    }
                    ann = ann->next;
                }
                if (ins == invoke_ins) {
                    /* Found it; see if we have any handlers active. If so, we
                     * will continue walking to collect goto annotations. */
                    found_invoke = 1;
                    for (i = 0; i < orig_handlers; i++)
                        active_handlers_at_invoke += active[i];
                    if (!active_handlers_at_invoke)
                        break;
                }
                ins = ins->next;
            }
            if (found_invoke && !active_handlers_at_invoke)
                break;
            bb = bb->linear_next;
        }

        /* If we found handlers active at the point of invoke, duplicate them
         * in the handlers table and add annotations. */
        if (active_handlers_at_invoke) {
            MVMuint32 insert_pos = inliner->num_handlers + inlinee->num_handlers;
            resize_handlers_table(tc, inliner, insert_pos + active_handlers_at_invoke);
            for (i = orig_handlers - 1; i >= 0; i--) {
                if (active[i]) {
                    /* Add handler start annotation to first inlinee instruction. */
                    MVMSpeshAnn *new_ann = MVM_spesh_alloc(tc, inliner, sizeof(MVMSpeshAnn));
                    new_ann->type = MVM_SPESH_ANN_FH_START;
                    new_ann->data.frame_handler_index = insert_pos;
                    new_ann->next = inlinee_first_bb->first_ins->annotations;
                    inlinee_first_bb->first_ins->annotations = new_ann;

                    /* Add handler end annotation to last inlinee instruction. */
                    new_ann = MVM_spesh_alloc(tc, inliner, sizeof(MVMSpeshAnn));
                    new_ann->type = MVM_SPESH_ANN_FH_END;
                    new_ann->data.frame_handler_index = insert_pos;
                    new_ann->next = inlinee_last_bb->last_ins->annotations;
                    inlinee_last_bb->last_ins->annotations = new_ann;

                    /* Add handler goto annotation to original target in inliner. */
                    new_ann = MVM_spesh_alloc(tc, inliner, sizeof(MVMSpeshAnn));
                    new_ann->type = MVM_SPESH_ANN_FH_GOTO;
                    new_ann->data.frame_handler_index = insert_pos;
                    new_ann->next = handler_goto_ins[i]->annotations;
                    handler_goto_ins[i]->annotations = new_ann;

                    /* Copy handler entry to new slot. */
                    memcpy(inliner->handlers + insert_pos, inliner->handlers + i,
                        sizeof(MVMFrameHandler));
                    insert_pos++;
                }
            }
        }
    }

    /* Update total locals, lexicals, basic blocks, and handlers of the
     * inliner. */
    inliner->num_bbs      += inlinee->num_bbs - 1;
    inliner->num_locals   += inlinee->num_locals;
    inliner->num_lexicals += inlinee->num_lexicals;
    inliner->num_handlers += inlinee->num_handlers + active_handlers_at_invoke;
}
Пример #6
0
/* Merges the inlinee's spesh graph into the inliner. */
static void merge_graph(MVMThreadContext *tc, MVMSpeshGraph *inliner,
                 MVMSpeshGraph *inlinee, MVMCode *inlinee_code,
                 MVMSpeshIns *invoke_ins) {
    MVMSpeshFacts **merged_facts;
    MVMuint16      *merged_fact_counts;
    MVMint32        i, total_inlines, orig_deopt_addrs;

    /* If the inliner and inlinee are from different compilation units, we
     * potentially have to fix up extra things. */
    MVMint32 same_comp_unit = inliner->sf->body.cu == inlinee->sf->body.cu;

    /* Renumber the locals, lexicals, and basic blocks of the inlinee; also
     * re-write any indexes in annotations that need it. */
    MVMSpeshBB *bb = inlinee->entry;
    while (bb) {
        MVMSpeshIns *ins = bb->first_ins;
        while (ins) {
            MVMuint16    opcode = ins->info->opcode;
            MVMSpeshAnn *ann    = ins->annotations;
            while (ann) {
                switch (ann->type) {
                case MVM_SPESH_ANN_FH_START:
                case MVM_SPESH_ANN_FH_END:
                case MVM_SPESH_ANN_FH_GOTO:
                    ann->data.frame_handler_index += inliner->num_handlers;
                    break;
                case MVM_SPESH_ANN_DEOPT_INLINE:
                    ann->data.deopt_idx += inliner->num_deopt_addrs;
                    break;
                case MVM_SPESH_ANN_INLINE_START:
                case MVM_SPESH_ANN_INLINE_END:
                    ann->data.inline_idx += inliner->num_inlines;
                    break;
                }
                ann = ann->next;
            }

            if (opcode == MVM_SSA_PHI) {
                for (i = 0; i < ins->info->num_operands; i++)
                    ins->operands[i].reg.orig += inliner->num_locals;
            }
            else {
                for (i = 0; i < ins->info->num_operands; i++) {
                    MVMuint8 flags = ins->info->operands[i];
                    switch (flags & MVM_operand_rw_mask) {
                    case MVM_operand_read_reg:
                    case MVM_operand_write_reg:
                        ins->operands[i].reg.orig += inliner->num_locals;
                        break;
                    case MVM_operand_read_lex:
                    case MVM_operand_write_lex:
                        ins->operands[i].lex.idx += inliner->num_lexicals;
                        break;
                    default: {
                        MVMuint32 type = flags & MVM_operand_type_mask;
                        if (type == MVM_operand_spesh_slot) {
                            ins->operands[i].lit_i16 += inliner->num_spesh_slots;
                        }
                        else if (type == MVM_operand_callsite) {
                            if (!same_comp_unit)
                                fix_callsite(tc, inliner, inlinee, &(ins->operands[i]));
                        }
                        else if (type == MVM_operand_coderef) {
                            if (!same_comp_unit)
                                fix_coderef(tc, inliner, inlinee, &(ins->operands[i]));
                        }
                        else if (type == MVM_operand_str) {
                            if (!same_comp_unit)
                                fix_str(tc, inliner, inlinee, &(ins->operands[i]));
                        }
                        break;
                        }
                    }
                }
            }

            ins = ins->next;
        }
        bb->idx += inliner->num_bbs - 1; /* -1 as we won't include entry */
        bb->inlined = 1;
        bb = bb->linear_next;
    }

    /* Incorporate the basic blocks by concatening them onto the end of the
     * linear_next chain of the inliner; skip the inlinee's fake entry BB. */
    bb = inliner->entry;
    while (bb) {
        if (!bb->linear_next) {
            /* Found the end; insert and we're done. */
            bb->linear_next = inlinee->entry->linear_next;
            bb = NULL;
        }
        else {
            bb = bb->linear_next;
        }
    }

    /* Merge facts. */
    merged_facts = MVM_spesh_alloc(tc, inliner,
        (inliner->num_locals + inlinee->num_locals) * sizeof(MVMSpeshFacts *));
    memcpy(merged_facts, inliner->facts,
        inliner->num_locals * sizeof(MVMSpeshFacts *));
    memcpy(merged_facts + inliner->num_locals, inlinee->facts,
        inlinee->num_locals * sizeof(MVMSpeshFacts *));
    inliner->facts = merged_facts;
    merged_fact_counts = MVM_spesh_alloc(tc, inliner,
        (inliner->num_locals + inlinee->num_locals) * sizeof(MVMuint16));
    memcpy(merged_fact_counts, inliner->fact_counts,
        inliner->num_locals * sizeof(MVMuint16));
    memcpy(merged_fact_counts + inliner->num_locals, inlinee->fact_counts,
        inlinee->num_locals * sizeof(MVMuint16));
    inliner->fact_counts = merged_fact_counts;

    /* Copy over spesh slots. */
    for (i = 0; i < inlinee->num_spesh_slots; i++)
        MVM_spesh_add_spesh_slot(tc, inliner, inlinee->spesh_slots[i]);

    /* If they are from separate compilation units, make another pass through
     * to fix up on wvals. Note we can't do this in the first pass as we must
     * not modify the spesh slots once we've got started with the rewrites.
     * Now we've resolved all that, we're good to map wvals elsewhere into
     * some extra spesh slots. */
    if (!same_comp_unit) {
        bb = inlinee->entry;
        while (bb) {
            MVMSpeshIns *ins = bb->first_ins;
            while (ins) {
                MVMuint16 opcode = ins->info->opcode;
                if (opcode == MVM_OP_wval || opcode == MVM_OP_wval_wide)
                    fix_wval(tc, inliner, inlinee, ins);
                ins = ins->next;
            }
            bb = bb->linear_next;
        }
    }

    /* Merge de-opt tables, if needed. */
    orig_deopt_addrs = inliner->num_deopt_addrs;
    if (inlinee->num_deopt_addrs) {
        assert(inlinee->deopt_addrs != inliner->deopt_addrs);
        inliner->alloc_deopt_addrs += inlinee->alloc_deopt_addrs;
        if (inliner->deopt_addrs)
            inliner->deopt_addrs = MVM_realloc(inliner->deopt_addrs,
                inliner->alloc_deopt_addrs * sizeof(MVMint32) * 2);
        else
            inliner->deopt_addrs = MVM_malloc(inliner->alloc_deopt_addrs * sizeof(MVMint32) * 2);
        memcpy(inliner->deopt_addrs + inliner->num_deopt_addrs * 2,
            inlinee->deopt_addrs, inlinee->alloc_deopt_addrs * sizeof(MVMint32) * 2);
        inliner->num_deopt_addrs += inlinee->num_deopt_addrs;
    }

    /* Merge inlines table, and add us an entry too. */
    total_inlines = inliner->num_inlines + inlinee->num_inlines + 1;
    inliner->inlines = inliner->num_inlines
        ? MVM_realloc(inliner->inlines, total_inlines * sizeof(MVMSpeshInline))
        : MVM_malloc(total_inlines * sizeof(MVMSpeshInline));
    memcpy(inliner->inlines + inliner->num_inlines, inlinee->inlines,
        inlinee->num_inlines * sizeof(MVMSpeshInline));
    for (i = inliner->num_inlines; i < total_inlines - 1; i++) {
        inliner->inlines[i].locals_start += inliner->num_locals;
        inliner->inlines[i].lexicals_start += inliner->num_lexicals;
        inliner->inlines[i].return_deopt_idx += orig_deopt_addrs;
    }
    inliner->inlines[total_inlines - 1].code           = inlinee_code;
    inliner->inlines[total_inlines - 1].g              = inlinee;
    inliner->inlines[total_inlines - 1].locals_start   = inliner->num_locals;
    inliner->inlines[total_inlines - 1].lexicals_start = inliner->num_lexicals;
    switch (invoke_ins->info->opcode) {
    case MVM_OP_invoke_v:
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_VOID;
        break;
    case MVM_OP_invoke_o:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_OBJ;
        break;
    case MVM_OP_invoke_i:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_INT;
        break;
    case MVM_OP_invoke_n:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_NUM;
        break;
    case MVM_OP_invoke_s:
        inliner->inlines[total_inlines - 1].res_reg = invoke_ins->operands[0].reg.orig;
        inliner->inlines[total_inlines - 1].res_type = MVM_RETURN_STR;
        break;
    default:
        MVM_exception_throw_adhoc(tc, "Spesh inline: unknown invoke instruction");
    }
    inliner->inlines[total_inlines - 1].return_deopt_idx = return_deopt_idx(tc, invoke_ins);
    inliner->num_inlines = total_inlines;

    /* Create/update per-specialization local and lexical type maps. */
    if (!inliner->local_types) {
        MVMint32 local_types_size = inliner->num_locals * sizeof(MVMuint16);
        inliner->local_types = MVM_malloc(local_types_size);
        memcpy(inliner->local_types, inliner->sf->body.local_types, local_types_size);
    }
    inliner->local_types = MVM_realloc(inliner->local_types,
        (inliner->num_locals + inlinee->num_locals) * sizeof(MVMuint16));
    memcpy(inliner->local_types + inliner->num_locals,
        inlinee->local_types ? inlinee->local_types : inlinee->sf->body.local_types,
        inlinee->num_locals * sizeof(MVMuint16));
    if (!inliner->lexical_types) {
        MVMint32 lexical_types_size = inliner->num_lexicals * sizeof(MVMuint16);
        inliner->lexical_types = MVM_malloc(lexical_types_size);
        memcpy(inliner->lexical_types, inliner->sf->body.lexical_types, lexical_types_size);
    }
    inliner->lexical_types = MVM_realloc(inliner->lexical_types,
        (inliner->num_lexicals + inlinee->num_lexicals) * sizeof(MVMuint16));
    memcpy(inliner->lexical_types + inliner->num_lexicals,
        inlinee->lexical_types ? inlinee->lexical_types : inlinee->sf->body.lexical_types,
        inlinee->num_lexicals * sizeof(MVMuint16));

    /* Merge handlers. */
    if (inlinee->num_handlers) {
        MVMuint32 total_handlers = inliner->num_handlers + inlinee->num_handlers;
        if (inliner->handlers == inliner->sf->body.handlers) {
            /* Original handlers table; need a copy. */
            MVMFrameHandler *new_handlers = MVM_malloc(total_handlers * sizeof(MVMFrameHandler));
            memcpy(new_handlers, inliner->handlers,
                inliner->num_handlers * sizeof(MVMFrameHandler));
            inliner->handlers = new_handlers;
        }
        else {
            /* Probably already did some inlines into this frame; resize. */
            inliner->handlers = MVM_realloc(inliner->handlers,
                total_handlers * sizeof(MVMFrameHandler));
        }
        memcpy(inliner->handlers + inliner->num_handlers, inlinee->handlers,
            inlinee->num_handlers * sizeof(MVMFrameHandler));
        for (i = inliner->num_handlers; i < total_handlers; i++) {
            inliner->handlers[i].block_reg += inliner->num_locals;
            inliner->handlers[i].label_reg += inliner->num_locals;
        }
    }

    /* Update total locals, lexicals, basic blocks, and handlers of the
     * inliner. */
    inliner->num_bbs      += inlinee->num_bbs - 1;
    inliner->num_locals   += inlinee->num_locals;
    inliner->num_lexicals += inlinee->num_lexicals;
    inliner->num_handlers += inlinee->num_handlers;
}