Esempio n. 1
0
static void twoover(void)
{
	const cell tmp = GETITEM(3);
	const cell tmp2 = GETITEM(2);
	PUSH(tmp);
	PUSH(tmp2);
}
Esempio n. 2
0
static void twodup(void)
{
	cell tmp = GETITEM(1);
	PUSH(tmp);
	tmp = GETITEM(1);
	PUSH(tmp);
}
Esempio n. 3
0
/*
================
Use_Weapon

Make the weapon ready if there is ammo
================
*/
void Use_Weapon (edict_t *ent, const gitem_t *item)
{
	int				ammo_index;
	const gitem_t	*ammo_item;

	// see if we're already using it
	if (item == ent->client->weapon)
		return;

	if (item->ammoindex && !g_select_empty->value && !(item->flags & IT_AMMO))
	{
		ammo_item = GETITEM (item->ammoindex);
		ammo_index = item->ammoindex;

		if (!ent->client->inventory[ammo_index])
		{
			gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
			return;
		}

		if (ent->client->inventory[ammo_index] < item->quantity)
		{
			gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
			return;
		}
	}

	// change to this weapon when down
	ent->client->newweapon = item;
}
Esempio n. 4
0
qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
{
	int				index;
	const gitem_t	*ammo;

	index = ITEM_INDEX(ent->item);

	if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY)) 
		&& other->client->inventory[index])
	{
		if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
			return false;	// leave the weapon for others to pickup
	}

	other->client->inventory[index]++;

	if (!(ent->spawnflags & DROPPED_ITEM) )
	{
		// give them some ammo with it
		ammo = GETITEM (ent->item->ammoindex);
		if ( (int)dmflags->value & DF_INFINITE_AMMO )
			Add_Ammo (other, ammo, 1000);
		else
			Add_Ammo (other, ammo, ammo->quantity);

		if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
		{
			if ((int)(dmflags->value) & DF_WEAPONS_STAY)
				ent->flags |= FL_RESPAWN;
			else
				SetRespawn (ent, 30);
		}
	}

	if (other->client->weapon != ent->item && 
		(other->client->inventory[index] == 1) &&
		other->client->weapon == GETITEM (ITEM_WEAPON_BLASTER))
		other->client->newweapon = ent->item;

	return true;
}
Esempio n. 5
0
/*
==========
Armor (long)
==========
*/
const char *TDM_Macro_LongArmor (edict_t *ent, size_t *length)
{
	static char	buff[32];
	int			index;
	int			power;
	int			count;

	index = ArmorIndex (ent);

	if (index == 0)
		count = 0;
	else
		count = ent->client->inventory[index];

	power = TDM_GetPowerArmorCount (ent);

	if (power == -1)
		*length = sprintf (buff, "A:%d %s", count, GETITEM(index)->pickup_name);
	else
		*length = sprintf (buff, "A:%d %s P:%d", count, GETITEM(index)->pickup_name, power);

	return buff;
}
Esempio n. 6
0
/*
==========
Weapon (short)
==========
*/
const char *TDM_Macro_ShortWeapon (edict_t *ent, size_t *length)
{
	static char	buff[16];

	if (!ent->client->weapon)
		return NULL;

	if (ent->client->weapon == GETITEM(ITEM_WEAPON_BLASTER))
		*length = sprintf (buff, "%s", ent->client->weapon->shortname);
	else
		*length = sprintf (buff, "%s:%d", ent->client->weapon->shortname, ent->client->inventory[ent->client->ammo_index]);

	return buff;
}
Esempio n. 7
0
/*
=================
NoAmmoWeaponChange
=================
*/
void NoAmmoWeaponChange (edict_t *ent)
{
	if ( ent->client->inventory[ITEM_AMMO_SLUGS]
		&&  ent->client->inventory[ITEM_WEAPON_RAILGUN] )
	{
		ent->client->newweapon = GETITEM (ITEM_WEAPON_RAILGUN);
		return;
	}
	if ( ent->client->inventory[ITEM_AMMO_CELLS]
		&&  ent->client->inventory[ITEM_WEAPON_HYPERBLASTER] )
	{
		ent->client->newweapon = GETITEM (ITEM_WEAPON_HYPERBLASTER);
		return;
	}
	if ( ent->client->inventory[ITEM_AMMO_BULLETS]
		&&  ent->client->inventory[ITEM_WEAPON_CHAINGUN] )
	{
		ent->client->newweapon = GETITEM (ITEM_WEAPON_CHAINGUN);
		return;
	}
	if ( ent->client->inventory[ITEM_AMMO_BULLETS]
		&&  ent->client->inventory[ITEM_WEAPON_MACHINEGUN] )
	{
		ent->client->newweapon = GETITEM (ITEM_WEAPON_MACHINEGUN);
		return;
	}
	if ( ent->client->inventory[ITEM_AMMO_SHELLS] > 1
		&&  ent->client->inventory[ITEM_WEAPON_SUPERSHOTGUN] )
	{
		ent->client->newweapon = GETITEM (ITEM_WEAPON_SUPERSHOTGUN);
		return;
	}
	if ( ent->client->inventory[ITEM_AMMO_SHELLS]
		&&  ent->client->inventory[ITEM_WEAPON_SHOTGUN] )
	{
		ent->client->newweapon = GETITEM (ITEM_WEAPON_SHOTGUN);
		return;
	}
	ent->client->newweapon = GETITEM (ITEM_WEAPON_BLASTER);
}
Esempio n. 8
0
static void over(void)
{
	const cell tmp = GETITEM(1);
	PUSH(tmp);
}
Esempio n. 9
0
/*QUAKED worldspawn (0 0 0) ?

Only used for the world.
"sky"	environment map name
"skyaxis"	vector axis for rotating sky
"skyrotate"	speed of rotation in degrees/second
"sounds"	music cd track number
"gravity"	800 is default gravity
"message"	text to print at user logon
*/
void SP_worldspawn (edict_t *ent)
{
	ent->movetype = MOVETYPE_PUSH;
	ent->solid = SOLID_BSP;
	ent->inuse = true;			// since the world doesn't use G_Spawn()
	ent->s.modelindex = 1;		// world model is always index 1

	//---------------

	// reserve some spots for dead player bodies for coop / deathmatch
	InitBodyQue ();

	// set configstrings for items
	SetItemNames ();

	if (st.nextmap)
		strcpy (level.nextmap, st.nextmap);

	// make some data visible to the server

	if (ent->message && ent->message[0])
	{
		gi.configstring (CS_NAME, ent->message);
		strncpy (level.level_name, ent->message, sizeof(level.level_name));
	}
	else
		strncpy (level.level_name, level.mapname, sizeof(level.level_name));

	if (st.sky && st.sky[0])
		gi.configstring (CS_SKY, st.sky);
	else
		gi.configstring (CS_SKY, "unit1_");

	gi.configstring (CS_SKYROTATE, va("%f", st.skyrotate) );

	gi.configstring (CS_SKYAXIS, va("%f %f %f",
		st.skyaxis[0], st.skyaxis[1], st.skyaxis[2]) );

	gi.configstring (CS_CDTRACK, va("%i", ent->sounds) );

	gi.configstring (CS_MAXCLIENTS, va("%i", game.maxclients ) );

	// status bar program
	// wision: we send this as unicast on every player's connect
	// r1: but we send it globally too to avoid bugging out gtv/etc
	gi.configstring (CS_STATUSBAR, dm_statusbar);

	//---------------

	// help icon for statusbar
	gi.imageindex ("i_help");
	level.pic_health = gi.imageindex ("i_health");
	gi.imageindex ("help");
	gi.imageindex ("field_3");

	if (!st.gravity)
		gi.cvar_set("sv_gravity", "800");
	else
		gi.cvar_set("sv_gravity", st.gravity);

	snd_fry = gi.soundindex ("player/fry.wav");	// standing in lava / slime

	PrecacheItem (GETITEM (ITEM_WEAPON_BLASTER));

	gi.soundindex ("player/lava1.wav");
	gi.soundindex ("player/lava2.wav");

	gi.soundindex ("misc/pc_up.wav");
	gi.soundindex ("misc/talk1.wav");

	gi.soundindex ("misc/udeath.wav");

	// gibs
	gi.soundindex ("items/respawn1.wav");

	// sexed sounds
	//ugly hack for tdm / invisible eyes mode, we reserve soundindexes directly

	/*gi.soundindex ("*death1.wav");
	gi.soundindex ("*death2.wav");
	gi.soundindex ("*death3.wav");
	gi.soundindex ("*death4.wav");
	gi.soundindex ("*fall1.wav");
	gi.soundindex ("*fall2.wav");	
	gi.soundindex ("*gurp1.wav");		// drowning damage
	gi.soundindex ("*gurp2.wav");	
	gi.soundindex ("*jump1.wav");		// player jump
	gi.soundindex ("*pain25_1.wav");
	gi.soundindex ("*pain25_2.wav");
	gi.soundindex ("*pain50_1.wav");
	gi.soundindex ("*pain50_2.wav");
	gi.soundindex ("*pain75_1.wav");
	gi.soundindex ("*pain75_2.wav");
	gi.soundindex ("*pain100_1.wav");
	gi.soundindex ("*pain100_2.wav");*/


	// sexed models
	// THIS ORDER MUST MATCH THE DEFINES IN g_local.h
	// you can add more, max 15
	gi.modelindex ("#w_blaster.md2");
	gi.modelindex ("#w_shotgun.md2");
	gi.modelindex ("#w_sshotgun.md2");
	gi.modelindex ("#w_machinegun.md2");
	gi.modelindex ("#w_chaingun.md2");
	gi.modelindex ("#a_grenades.md2");
	gi.modelindex ("#w_glauncher.md2");
	gi.modelindex ("#w_rlauncher.md2");
	gi.modelindex ("#w_hyperblaster.md2");
	gi.modelindex ("#w_railgun.md2");
	gi.modelindex ("#w_bfg.md2");

	//-------------------

	gi.soundindex ("player/gasp1.wav");		// gasping for air
	gi.soundindex ("player/gasp2.wav");		// head breaking surface, not gasping

	gi.soundindex ("player/watr_in.wav");	// feet hitting water
	gi.soundindex ("player/watr_out.wav");	// feet leaving water

	gi.soundindex ("player/watr_un.wav");	// head going underwater
	
	gi.soundindex ("player/u_breath1.wav");
	gi.soundindex ("player/u_breath2.wav");

	gi.soundindex ("items/pkup.wav");		// bonus item pickup
	gi.soundindex ("world/land.wav");		// landing thud
	gi.soundindex ("misc/h2ohit1.wav");		// landing splash

	gi.soundindex ("items/damage.wav");
	gi.soundindex ("items/protect.wav");
	gi.soundindex ("items/protect4.wav");
	gi.soundindex ("weapons/noammo.wav");

	gi.soundindex ("infantry/inflies1.wav");

	sm_meat_index = gi.modelindex ("models/objects/gibs/sm_meat/tris.md2");
	gi.modelindex ("models/objects/gibs/arm/tris.md2");
	gi.modelindex ("models/objects/gibs/bone/tris.md2");
	gi.modelindex ("models/objects/gibs/bone2/tris.md2");
	gi.modelindex ("models/objects/gibs/chest/tris.md2");
	gi.modelindex ("models/objects/gibs/skull/tris.md2");
	gi.modelindex ("models/objects/gibs/head2/tris.md2");

	//this is to force precache of the opentdm 'invisible player' model so it
	//is auto downloaded (hopefully!)
	//gi.modelindex ("players/opentdm/tris.md2");
	//gi.modelindex ("players/opentdm/weapon.md2");

	//gi.configstring (CS_PLAYERSKINS+255, "null\\opentdm/null");

//
// Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
//

	// 0 normal
	gi.configstring(CS_LIGHTS+0, "m");
	
	// 1 FLICKER (first variety)
	gi.configstring(CS_LIGHTS+1, "mmnmmommommnonmmonqnmmo");
	
	// 2 SLOW STRONG PULSE
	gi.configstring(CS_LIGHTS+2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
	
	// 3 CANDLE (first variety)
	gi.configstring(CS_LIGHTS+3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
	
	// 4 FAST STROBE
	gi.configstring(CS_LIGHTS+4, "mamamamamama");
	
	// 5 GENTLE PULSE 1
	gi.configstring(CS_LIGHTS+5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
	
	// 6 FLICKER (second variety)
	gi.configstring(CS_LIGHTS+6, "nmonqnmomnmomomno");
	
	// 7 CANDLE (second variety)
	gi.configstring(CS_LIGHTS+7, "mmmaaaabcdefgmmmmaaaammmaamm");
	
	// 8 CANDLE (third variety)
	gi.configstring(CS_LIGHTS+8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
	
	// 9 SLOW STROBE (fourth variety)
	gi.configstring(CS_LIGHTS+9, "aaaaaaaazzzzzzzz");
	
	// 10 FLUORESCENT FLICKER
	gi.configstring(CS_LIGHTS+10, "mmamammmmammamamaaamammma");

	// 11 SLOW PULSE NOT FADE TO BLACK
	gi.configstring(CS_LIGHTS+11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
	
	// styles 32-62 are assigned by the light program for switchable lights

	// 63 testing
	gi.configstring(CS_LIGHTS+63, "a");
}
Esempio n. 10
0
/*
==============
TDM_SetInitialItems
==============
Give a client an initial weapon/item loadout depending on match mode
*/
void TDM_SetInitialItems (edict_t *ent)
{
	gclient_t		*client;
	const gitem_t	*item;
	int				i;

	client = ent->client;


	client->max_bullets		= 200;
	client->max_shells		= 100;
	client->max_rockets		= 50;
	client->max_grenades	= 50;
	client->max_cells		= 200;
	client->max_slugs		= 50;

	switch (tdm_match_status)
	{
		case MM_WARMUP:
			//wision: spawn with rail in insta
			if (g_gamemode->value == GAMEMODE_ITDM)
			{
				item = GETITEM (ITEM_WEAPON_RAILGUN);
				Add_Ammo (ent, GETITEM(item->ammoindex), 1000);
				client->weapon = item;
				client->selected_item = ITEM_INDEX(item);
				client->inventory[client->selected_item] = 1;
			}
			else
			{
				for (i = 1; i < game.num_items; i++)
				{
					item = GETITEM (i);
					//wision: BFG sucks in warmup :X
					if ((item->flags & IT_WEAPON) && i != ITEM_WEAPON_BFG)
					{
						client->inventory[i] = 1;
						if (item->ammoindex)
							Add_Ammo (ent, GETITEM(item->ammoindex), 1000);
					}
				}

				//spawn with RL up
				if (!client->pers.last_weapon || client->inventory[ITEM_INDEX (client->pers.last_weapon)] == 0)
				{
					client->selected_item = ITEM_WEAPON_ROCKETLAUNCHER;
					client->weapon = GETITEM (ITEM_WEAPON_ROCKETLAUNCHER);
				}
				else
				{
					client->weapon = client->pers.last_weapon;
					client->selected_item = ITEM_INDEX (client->pers.last_weapon);
				}
			}
			client->inventory[ITEM_ITEM_ARMOR_BODY] = 100;
			break;

		default:
			//wision: spawn with rail in insta
			if (g_gamemode->value == GAMEMODE_ITDM)
			{
				item = GETITEM (ITEM_WEAPON_RAILGUN);
				Add_Ammo (ent, GETITEM(item->ammoindex), 1000);
			}
			else
				item = GETITEM (ITEM_WEAPON_BLASTER);
			client->weapon = item;
			client->selected_item = ITEM_INDEX(item);
			client->inventory[client->selected_item] = 1;
			break;
	}
}
Esempio n. 11
0
File: vm.c Progetto: talkspoon/cobj
/*
 * Evaluate a function object into a object.
 */
COObject *
vm_eval(COObject *func, COObject *globals)
{
#define JUMPBY(offset)  next_code += offset
#define JUMPTO(offset)  next_code = first_code + offset
#define NEXTOP()        (*next_code++)
#define NEXTARG()       (next_code += 2, (next_code[-1]<<8) + next_code[-2])
#define GETITEM(v, i)   COTuple_GET_ITEM((COTupleObject *)(v), i)
#define GETLOCAL(i)     (fastlocals[i])
#define SETLOCAL(i, v)                  \
    do {                                \
        COObject *tmp = GETLOCAL(i);    \
        GETLOCAL(i) = v;                \
        CO_XDECREF(tmp);                \
    } while (0);
#define PUSH(o)         (*stack_top++ = (o))
#define POP()           (*--stack_top)
#define TOP()           (stack_top[-1])
#define SET_TOP(o)      (stack_top[-1] = (o))
#define SECOND()        (stack_top[-2])
#define THIRD()         (stack_top[-3])
#define FOURTH()        (stack_top[-4])
#define PEEK(n)         (stack_top[-(n)])
#define STACK_ADJ(n)    (stack_top += n)
#define STACK_LEVEL()   ((int)(stack_top - TS(frame)->f_stack))
#define UNWIND_BLOCK(b) \
    do { \
        while (STACK_LEVEL() > (b)->fb_level) { \
            COObject *o = POP(); \
            CO_XDECREF(o); \
        } \
    } while (0)

    COCodeObject *code;
    COObject *names;
    COObject *consts;
    COObject *localnames;
    COObject *funcargs = COList_New(0);

    COObject **fastlocals;
    COObject **stack_top;       /* Stack top, points to next free slot in stack */

    unsigned char *next_code;
    unsigned char *first_code;
    unsigned char opcode;       /* Current opcode */
    int oparg;                  /* Current opcode argument, if any */
    COObject *x;                /* Result object -- NULL if error */
    COObject *o1, *o2, *o3;     /* Temporary objects popped of stack */
    int status;                 /* VM status */
    int err;                    /* C function error code */
    status = STATUS_NONE;

    TS(frame) =
        (COFrameObject *)COFrame_New((COObject *)TS(frame), func, globals);

new_frame:                     /* reentry point when function call/return */
    code = (COCodeObject *)((COFunctionObject *)TS(frame)->f_func)->func_code;
    stack_top = TS(frame)->f_stacktop;
    names = code->co_names;
    localnames = code->co_localnames;
    consts = code->co_consts;
    first_code = (unsigned char *)COBytes_AsString(code->co_code);
    next_code = first_code + TS(frame)->f_lasti;
    fastlocals = TS(frame)->f_extraplus;

    /* Parse arguments. */
    if (COList_GET_SIZE(funcargs)) {
        // check arguments count
        if (code->co_argcount != COList_GET_SIZE(funcargs)) {
            COErr_Format(COException_ValueError,
                         "takes exactly %d arguments (%d given)",
                         code->co_argcount, COList_Size(funcargs));
            status = STATUS_EXCEPTION;
            goto fast_end;
        }
        size_t n = COList_Size(funcargs);
        for (int i = 0; i < n; i++) {
            x = COList_GetItem(funcargs, 0);
            CO_INCREF(x);
            SETLOCAL(n - i - 1, x);
            COList_DelItem(funcargs, 0);
        }
    }

    for (;;) {
        opcode = NEXTOP();
        switch (opcode) {
        case OP_BINARY_ADD:
            o1 = POP();
            o2 = TOP();
            if (COStr_Check(o1) && COStr_Check(o2)) {
                COStr_Concat(&o2, o1);
                x = o2;
                goto skip_decref_o2;
            } else {
                x = COInt_Type.tp_int_interface->int_add(o1, o2);
            }
            CO_DECREF(o2);
skip_decref_o2:
            CO_DECREF(o1);
            SET_TOP(x);
            if (!x) {
                status = STATUS_EXCEPTION;
                goto fast_end;
            }
            break;
        case OP_BINARY_SUB:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_sub(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_MUL:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_mul(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_DIV:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_div(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_MOD:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_mod(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_SL:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_lshift(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_SR:
            o1 = POP();
            o2 = TOP();
            x = COInt_Type.tp_int_interface->int_rshift(o2, o1);
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_BINARY_SUBSCRIPT:
            o1 = POP();
            o2 = TOP();
            if (!CO_TYPE(o2)->tp_mapping_interface) {
                COErr_Format(COException_TypeError,
                             "'%.200s' object is not subscriptable",
                             CO_TYPE(o2)->tp_name);
                status = STATUS_EXCEPTION;
            } else {
                x = CO_TYPE(o2)->tp_mapping_interface->mp_subscript(o2, o1);
                if (!x) {
                    status = STATUS_EXCEPTION;
                    goto fast_end;
                }
            }
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_CMP:
            o1 = POP();
            o2 = TOP();
            oparg = NEXTARG();
            x = vm_cmp(oparg, o1, o2);
            if (!x) {
                status = STATUS_EXCEPTION;
                goto fast_end;
            }
            CO_DECREF(o1);
            CO_DECREF(o2);
            SET_TOP(x);
            break;
        case OP_UNARY_NEGATE:
            o1 = TOP();
            x = COInt_Type.tp_int_interface->int_neg(o1);
            CO_DECREF(o1);
            SET_TOP(x);
            break;
        case OP_UNARY_INVERT:
            o1 = TOP();
            x = COInt_Type.tp_int_interface->int_invert(o1);
            CO_DECREF(o1);
            SET_TOP(x);
            break;
        case OP_LOAD_LOCAL:
            oparg = NEXTARG();
            x = GETLOCAL(oparg);
            CO_INCREF(x);
            PUSH(x);
            break;
        case OP_LOAD_NAME:
            oparg = NEXTARG();
            o1 = GETITEM(names, oparg);
            x = COObject_get(o1);
            if (!x) {
                COErr_Format(COException_NameError, "name '%s' is not defined",
                             COStr_AsString(o1));
                status = STATUS_EXCEPTION;
                goto fast_end;
            }
            CO_INCREF(x);
            PUSH(x);
            break;
        case OP_LOAD_UPVAL:
            oparg = NEXTARG();
            o1 = COTuple_GET_ITEM(((COFunctionObject *)func)->func_upvalues,
                                  oparg);
            o2 = COCell_Get(o1);
            PUSH(o2);
            break;
        case OP_LOAD_CONST:
            oparg = NEXTARG();
            x = GETITEM(consts, oparg);
            CO_INCREF(x);
            PUSH(x);
            break;
        case OP_BUILD_TUPLE:
            oparg = NEXTARG();
            x = COTuple_New(oparg);
            if (x != NULL) {
                for (; --oparg >= 0;) {
                    o1 = POP();
                    COTuple_SetItem(x, oparg, o1);
                    CO_DECREF(o1);
                }
                PUSH(x);
            }
            break;
        case OP_BUILD_LIST:
            oparg = NEXTARG();
            x = COList_New(oparg);
            if (x != NULL) {
                for (; --oparg >= 0;) {
                    o1 = POP();
                    COList_SetItem(x, oparg, o1);
                    CO_DECREF(o1);
                }
                PUSH(x);
            }
            break;
        case OP_DICT_BUILD:
            oparg = NEXTARG();
            x = CODict_New();
            PUSH(x);
            break;
        case OP_DICT_ADD:
            o1 = POP();
            o2 = POP();
            o3 = POP();
            CODict_SetItem(o3, o2, o1);
            x = o3;
            CO_DECREF(o1);
            CO_DECREF(o2);
            PUSH(x);
            break;
        case OP_STORE_NAME:
            oparg = NEXTARG();
            o1 = GETITEM(names, oparg);
            o2 = POP();
            COObject_set(o1, o2);
            CO_DECREF(o2);
            break;
        case OP_STORE_UPVAL:
            oparg = NEXTARG();
            o1 = COTuple_GET_ITEM(((COFunctionObject *)func)->func_upvalues,
                                  oparg);
            o2 = POP();
            COCell_Set(o1, o2);
            CO_DECREF(o2);
            break;
        case OP_STORE_LOCAL:
            oparg = NEXTARG();
            o1 = POP();
            SETLOCAL(oparg, o1);
            break;
        case OP_JMPZ:
            oparg = NEXTARG();
            o1 = POP();
            if (o1 == CO_True) {
            } else if (o1 == CO_False) {
                JUMPTO(oparg);
            } else {
                err = COObject_IsTrue(o1);
                if (err > 0)
                    err = 0;
                else if (err == 0)
                    JUMPTO(oparg);
            }
            CO_DECREF(o1);
            break;
        case OP_JMP:
            oparg = NEXTARG();
            JUMPBY(oparg);
            break;
        case OP_JMPX:
            oparg = NEXTARG();
            JUMPTO(oparg);
            break;
        case OP_DECLARE_FUNCTION:
            o1 = POP();
            x = COFunction_New(o1);
            COCodeObject *c = (COCodeObject *)o1;
            for (int i = 0; i < CO_SIZE(c->co_upvals); i++) {
                COObject *name = COTuple_GET_ITEM(c->co_upvals, i);
                COObject *upvalue = COObject_get(name);
                if (!upvalue) {
                    // local variables 
                    for (int j = 0; j < COTuple_Size(localnames); j++) {
                        if (COObject_CompareBool
                            (COTuple_GET_ITEM(localnames, j), name, Cmp_EQ)) {
                            upvalue = GETLOCAL(j);
                        }
                    }
                }
                COObject *cell = COCell_New(upvalue);
                COTuple_SET_ITEM(((COFunctionObject *)x)->func_upvalues, i,
                                 cell);
            }
            CO_DECREF(o1);
            PUSH(x);
            break;
        case OP_CALL_FUNCTION:
            o1 = POP();
            oparg = NEXTARG();
            COObject *args = COTuple_New(oparg);
            while (--oparg >= 0) {
                o2 = POP();
                COTuple_SetItem(args, oparg, o2);
                CO_DECREF(o2);
            }

            if (COCFunction_Check(o1)) {
                COCFunction cfunc = COCFunction_GET_FUNCTION(o1);
                x = cfunc(NULL, args);
                CO_DECREF(o1);
                CO_DECREF(args);
                PUSH(x);
            } else if (COFunction_Check(o1)) {
                ssize_t i = CO_SIZE(args);
                while (--i >= 0) {
                    COList_Append(funcargs, COTuple_GET_ITEM(args, i));
                }
                CO_DECREF(args);
                TS(frame)->f_stacktop = stack_top;
                TS(frame)->f_lasti = (int)(next_code - first_code);
                TS(frame) =
                    (COFrameObject *)COFrame_New((COObject *)TS(frame), o1,
                                                 globals);
                CO_DECREF(o1);
                func = o1;
                goto new_frame;
            } else {
                x = COObject_Call(o1, args);
                CO_DECREF(args);
                CO_DECREF(o1);
                PUSH(x);
            }
            break;
        case OP_RETURN:
            o1 = POP();
            TS(frame)->f_stacktop = stack_top;
            TS(frame)->f_lasti = (int)(next_code - first_code);
            COFrameObject *old_frame = (COFrameObject *)TS(frame);
            TS(frame) = (COFrameObject *)old_frame->f_prev;
            CO_DECREF(old_frame);
            if (!TS(frame)) {
                CO_DECREF(o1);
                goto vm_exit;
            }
            // init function return
            *(TS(frame)->f_stacktop++) = o1;
            goto new_frame;
            break;
        case OP_SETUP_LOOP:
            oparg = NEXTARG();
            COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL());
            break;
        case OP_SETUP_TRY:
            oparg = NEXTARG();
            COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL());
            break;
        case OP_POP_BLOCK:
            {
                COFrameBlock *fb = COFrameBlock_Pop(TS(frame));
                UNWIND_BLOCK(fb);
            }
            break;
        case OP_POP_TRY:
            {
                COFrameBlock *fb = COFrameBlock_Pop(TS(frame));
                UNWIND_BLOCK(fb);
            }
            break;
        case OP_BREAK_LOOP:
            status = STATUS_BREAK;
            break;
        case OP_CONTINUE_LOOP:
            oparg = NEXTARG();
            status = STATUS_CONTINUE;
            break;
        case OP_THROW:
            oparg = NEXTARG();
            if (oparg == 1) {
                o1 = POP();
            } else if (oparg == 0) {
                o1 = CO_None;
            } else {
                error("error oparg");
            }
            status = STATUS_EXCEPTION;
            COErr_SetObject(COException_SystemError, o1);
            break;
        case OP_DUP_TOP:
            o1 = TOP();
            CO_INCREF(o1);
            PUSH(o1);
            break;
        case OP_POP_TOP:
            o1 = POP();
            CO_DECREF(o1);
            break;
        case OP_END_TRY:
            o1 = POP();
            COErr_SetString(COException_SystemError, COStr_AsString(o1));
            status = STATUS_EXCEPTION;
            CO_DECREF(o1);
            break;
        case OP_SETUP_FINALLY:
            oparg = NEXTARG();
            COFrameBlock_Setup(TS(frame), opcode, oparg, STACK_LEVEL());
            break;
        case OP_END_FINALLY:
            o1 = POP();
            if (o1 != CO_None) {
                COErr_SetString(COException_SystemError, COStr_AsString(o1));
                status = STATUS_EXCEPTION;
            }
            CO_DECREF(o1);
            break;
        case OP_STORE_SUBSCRIPT:
            o1 = TOP();
            o2 = SECOND();
            o3 = THIRD();
            STACK_ADJ(-3);
            if (COList_Check(o3)) {
                err = COList_SetItem(o3, COInt_AsSsize_t(o2), o1);
            } else if (CODict_Check(o3)) {
                CODict_SetItem(o3, o2, o1);
            } else {
                error("wrong store subscript");
            }
            CO_DECREF(o1);
            CO_DECREF(o2);
            CO_DECREF(o3);
            break;
        case OP_GET_ITER:
            o1 = TOP();
            x = COObject_GetIter(o1);
            CO_DECREF(o1);
            SET_TOP(x);
            break;
        case OP_FOR_ITER:
            oparg = NEXTARG();
            o1 = TOP();
            x = (*o1->co_type->tp_iternext) (o1);
            if (x) {
                PUSH(x);
                break;
            }
            o1 = POP();
            CO_DECREF(o1);
            JUMPTO(oparg);
            break;
        default:
            error("unknown handle for opcode(%ld)\n", opcode);
        }

fast_end:

        while (status != STATUS_NONE && TS(frame)->f_iblock > 0) {
            COFrameBlock *fb =
                &TS(frame)->f_blockstack[TS(frame)->f_iblock - 1];
            if (fb->fb_type == OP_SETUP_LOOP && status == STATUS_CONTINUE) {
                status = STATUS_NONE;
                JUMPTO(oparg);
                break;
            }
            TS(frame)->f_iblock--;
            UNWIND_BLOCK(fb);
            if (fb->fb_type == OP_SETUP_LOOP && status == STATUS_BREAK) {
                status = STATUS_NONE;
                JUMPTO(fb->fb_handler);
                break;
            }
            if (fb->fb_type == OP_SETUP_TRY && status == STATUS_EXCEPTION) {
                status = STATUS_NONE;
                COObject *exc, *val, *tb;
                COErr_Fetch(&exc, &val, &tb);
                PUSH(val);
                JUMPTO(fb->fb_handler);
                break;
            }
        }

        /* End the loop if we still have an error (or return) */
        x = NULL;
        if (status != STATUS_NONE)
            break;
    }

vm_exit:

    /* Clear frame stack. */
    while (TS(frame)) {
        COFrameObject *tmp_frame = (COFrameObject *)TS(frame)->f_prev;
        CO_DECREF(TS(frame));
        TS(frame) = tmp_frame;
    }

    return x;
}
Esempio n. 12
0
static PyObject *
eval_frame(PyFrameObject *f)
{
	LOG("> eval_frame\n"); {
	PyObject **stack_pointer; /* Next free slot in value stack */
	register unsigned char *next_instr;
	register int opcode=0;	/* Current opcode */
	register int oparg=0;	/* Current opcode argument, if any */
	register enum why_code why; /* Reason for block stack unwind */
	register int err;	/* Error status -- nonzero if error */
	register PyObject *x;	/* Result object -- NULL if error */
	register PyObject *t, *u, *v;	/* Temporary objects popped off stack */
	register PyObject *w;
	register PyObject **fastlocals, **freevars;
	PyObject *retval = NULL;	/* Return value */
	PyThreadState *tstate = PyThreadState_GET();
	PyCodeObject *co;

	unsigned char *first_instr;
	PyObject *names;
	PyObject *consts;

/* Tuple access macros */

#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i))

/* Code access macros */

#define INSTR_OFFSET()	(next_instr - first_instr)
#define NEXTOP()	(*next_instr++)
#define NEXTARG()	(next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
#define JUMPTO(x)	(next_instr = first_instr + (x))
#define JUMPBY(x)	(next_instr += (x))

/* OpCode prediction macros
	Some opcodes tend to come in pairs thus making it possible to predict
	the second code when the first is run.  For example, COMPARE_OP is often
	followed by JUMP_IF_FALSE or JUMP_IF_TRUE.  And, those opcodes are often
	followed by a POP_TOP.

	Verifying the prediction costs a single high-speed test of register
	variable against a constant.  If the pairing was good, then the
	processor has a high likelihood of making its own successful branch
	prediction which results in a nearly zero overhead transition to the
	next opcode.

	A successful prediction saves a trip through the eval-loop including
	its two unpredictable branches, the HASARG test and the switch-case.
*/

#define PREDICT(op)		if (*next_instr == op) goto PRED_##op
#define PREDICTED(op)		PRED_##op: next_instr++
#define PREDICTED_WITH_ARG(op)	PRED_##op: oparg = (next_instr[2]<<8) + \
				next_instr[1]; next_instr += 3

/* Stack manipulation macros */

#define STACK_LEVEL()	(stack_pointer - f->f_valuestack)
#define EMPTY()		(STACK_LEVEL() == 0)
#define TOP()		(stack_pointer[-1])
#define SECOND()	(stack_pointer[-2])
#define THIRD() 	(stack_pointer[-3])
#define FOURTH()	(stack_pointer[-4])
#define SET_TOP(v)	(stack_pointer[-1] = (v))
#define SET_SECOND(v)	(stack_pointer[-2] = (v))
#define SET_THIRD(v)	(stack_pointer[-3] = (v))
#define SET_FOURTH(v)	(stack_pointer[-4] = (v))
#define BASIC_STACKADJ(n)	(stack_pointer += n)
#define BASIC_PUSH(v)	(*stack_pointer++ = (v))
#define BASIC_POP()	(*--stack_pointer)

#define PUSH(v)		BASIC_PUSH(v)
#define POP()		BASIC_POP()
#define STACKADJ(n)	BASIC_STACKADJ(n)

/* Local variable macros */

#define GETLOCAL(i)	(fastlocals[i])

/* The SETLOCAL() macro must not DECREF the local variable in-place and
   then store the new value; it must copy the old value to a temporary
   value, then store the new value, and then DECREF the temporary value.
   This is because it is possible that during the DECREF the frame is
   accessed by other code (e.g. a __del__ method or gc.collect()) and the
   variable would be pointing to already-freed memory. */
#define SETLOCAL(i, value)	do { PyObject *tmp = GETLOCAL(i); \
				     GETLOCAL(i) = value; \
                                     Py_XDECREF(tmp); } while (0)

/* Start of code */

	if (f == NULL)
		return NULL;

	/* push frame */
	if (++tstate->recursion_depth > recursion_limit) {
		--tstate->recursion_depth;
		/* ERROR */
		tstate->frame = f->f_back;
		return NULL;
	}

	tstate->frame = f;

	/* tracing elided */

	co = f->f_code;
	names = co->co_names;
	consts = co->co_consts;
	fastlocals = f->f_localsplus;
	freevars = f->f_localsplus + f->f_nlocals;

	_PyCode_GETCODEPTR(co, &first_instr);

	/* An explanation is in order for the next line.

	   f->f_lasti now refers to the index of the last instruction
	   executed.  You might think this was obvious from the name, but
	   this wasn't always true before 2.3!  PyFrame_New now sets
	   f->f_lasti to -1 (i.e. the index *before* the first instruction)
	   and YIELD_VALUE doesn't fiddle with f_lasti any more.  So this
	   does work.  Promise. */
	next_instr = first_instr + f->f_lasti + 1;
	stack_pointer = f->f_stacktop;

	f->f_stacktop = NULL;	/* remains NULL unless yield suspends frame */

	why = WHY_NOT;
	err = 0;
	x = Py_None;	/* Not a reference, just anything non-NULL */
	w = NULL;

	for (;;) {

		/* Do periodic things.  Doing this every time through
		   the loop would add too much overhead, so we do it
		   only every Nth instruction.  We also do it if
		   ``things_to_do'' is set, i.e. when an asynchronous
		   event needs attention (e.g. a signal handler or
		   async I/O handler); see Py_AddPendingCall() and
		   Py_MakePendingCalls() above. */

		if (--_Py_Ticker < 0) {
			/* @@@ check for SETUP_FINALLY elided */

			_Py_Ticker = _Py_CheckInterval;
			tstate->tick_counter++;
			if (things_to_do) {
				if (Py_MakePendingCalls() < 0) {
					why = WHY_EXCEPTION;
					goto on_error;
				}
			}
		}

	fast_next_opcode:
		f->f_lasti = INSTR_OFFSET();

		/* Extract opcode and argument */

		opcode = NEXTOP();
		if (HAS_ARG(opcode))
			oparg = NEXTARG();

		/* Main switch on opcode */

		switch (opcode) {

		/* BEWARE!
		   It is essential that any operation that fails sets either
		   x to NULL, err to nonzero, or why to anything but WHY_NOT,
		   and that no operation that succeeds does this! */

		/* case STOP_CODE: this is an error! */

		case LOAD_FAST:
			x = GETLOCAL(oparg);
			if (x != NULL) {
				Py_INCREF(x);
				PUSH(x);
				goto fast_next_opcode;
			}
			/* ERROR? */
			break;

                case STORE_FAST:
                        v = POP();
                        SETLOCAL(oparg, v);
                        continue;

		case LOAD_CONST:
			x = GETITEM(consts, oparg);
			Py_INCREF(x);
			PUSH(x);
			goto fast_next_opcode;

		PREDICTED(POP_TOP);
		case POP_TOP:
			v = POP();
			Py_DECREF(v);
			goto fast_next_opcode;

		case UNARY_NOT:
			v = TOP();
			err = PyObject_IsTrue(v);
			Py_DECREF(v);
			if (err == 0) {
				Py_INCREF(Py_True);
				SET_TOP(Py_True);
				continue;
			}
			else if (err > 0) {
				Py_INCREF(Py_False);
				SET_TOP(Py_False);
				err = 0;
				continue;
			}
			STACKADJ(-1);
			break;

		case BINARY_MODULO:
			w = POP();
			v = TOP();
			x = PyNumber_Remainder(v, w);
			Py_DECREF(v);
			Py_DECREF(w);
			SET_TOP(x);
			if (x != NULL) continue;
			break;
			
		case BINARY_ADD:
			w = POP();
			v = TOP();
			if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
				/* INLINE: int + int */
				register long a, b, i;
				a = PyInt_AS_LONG(v);
				b = PyInt_AS_LONG(w);
				i = a + b;
				if ((i^a) < 0 && (i^b) < 0)
					goto slow_add;
				x = PyInt_FromLong(i);
			}
			else {
			  slow_add:
				Py_FatalError("slow add not supported.");
			}
			Py_DECREF(v);
			Py_DECREF(w);
			SET_TOP(x);
			if (x != NULL) continue;
			break;

                case STORE_SLICE+0:
                case STORE_SLICE+1:
                case STORE_SLICE+2:
                case STORE_SLICE+3:
                        if ((opcode-STORE_SLICE) & 2)
                                w = POP();
                        else
                                w = NULL;
                        if ((opcode-STORE_SLICE) & 1)
                                v = POP();
                        else
                                v = NULL;
                        u = POP();
                        t = POP();
                        err = assign_slice(u, v, w, t); /* u[v:w] = t */
                        Py_DECREF(t);
                        Py_DECREF(u);
                        Py_XDECREF(v);
                        Py_XDECREF(w);
                        if (err == 0) continue;
                        break;

                case STORE_SUBSCR:
                        w = POP();
                        v = POP();
                        u = POP();
                        /* v[w] = u */
                        err = PyObject_SetItem(v, w, u);
                        Py_DECREF(u);
                        Py_DECREF(v);
                        Py_DECREF(w);
                        if (err == 0) continue;
                        break;

                case BINARY_SUBSCR:
                        w = POP();
                        v = TOP();
                        if (PyList_CheckExact(v) && PyInt_CheckExact(w)) {
                                /* INLINE: list[int] */
                                long i = PyInt_AsLong(w);
                                if (i < 0)
                                        i += PyList_GET_SIZE(v);
                                if (i < 0 ||
                                    i >= PyList_GET_SIZE(v)) {
                                        /* ERROR */
                                        printf("list index out of range\n");
                                        x = NULL;
                                }
                                else {
                                        x = PyList_GET_ITEM(v, i);
                                        Py_INCREF(x);
                                }
                        }
                        else
                                x = PyObject_GetItem(v, w);
                        Py_DECREF(v);
                        Py_DECREF(w);
                        SET_TOP(x);
                        if (x != NULL) continue;
                        break;

		case BINARY_AND:
			w = POP();
			v = TOP();
			x = PyNumber_And(v, w);
			Py_DECREF(v);
			Py_DECREF(w);
			SET_TOP(x);
			if (x != NULL) continue;
			break;

		case PRINT_ITEM:
			v = POP();

			PyObject_Print(v);
			Py_DECREF(v);
			break;

		case PRINT_NEWLINE:
			printf("\n");
			break;

		case RETURN_VALUE:
			retval = POP();
			why = WHY_RETURN;
			break;

		case POP_BLOCK:
			{
				PyTryBlock *b = PyFrame_BlockPop(f);
				while (STACK_LEVEL() > b->b_level) {
					v = POP();
					Py_DECREF(v);
				}
			}
			break;

		case STORE_NAME:
			w = GETITEM(names, oparg);
			v = POP();
			if ((x = f->f_locals) == NULL) {
				/* ERROR */
				printf("STORE_NAME ERROR\n");
				break;
			}
			err = PyDict_SetItem(x, w, v);
			Py_DECREF(v);
			break;

		case LOAD_NAME:
			w = GETITEM(names, oparg);
			if ((x = f->f_locals) == NULL) {
				/* ERROR */
				printf("LOAD_NAME ERROR\n");
				break;
			}
			x = PyDict_GetItem(x, w);
			if (x == NULL) {
				x = PyDict_GetItem(f->f_globals, w);
				if (x == NULL) {
					x = PyDict_GetItem(f->f_builtins, w);
					if (x == NULL) {
						printf("can't find %s\n", ((PyStringObject *)w)->ob_sval);
						/* format_exc_check_arg */
						break;
					}
				}
			}
			Py_INCREF(x);
			PUSH(x);
			break;
			
		case LOAD_GLOBAL:
			w = GETITEM(names, oparg);
			if (PyString_CheckExact(w)) {
				/* Inline the PyDict_GetItem() calls.
				   WARNING: this is an extreme speed hack.
				   Do not try this at home. */
				long hash = ((PyStringObject *)w)->ob_shash;
				if (hash != -1) {
					PyDictObject *d;
					d = (PyDictObject *)(f->f_globals);
					x = d->ma_lookup(d, w, hash)->me_value;
					if (x != NULL) {
						Py_INCREF(x);
						PUSH(x);
						continue;
					}
					d = (PyDictObject *)(f->f_builtins);
					x = d->ma_lookup(d, w, hash)->me_value;
					if (x != NULL) {
						Py_INCREF(x);
						PUSH(x);
						continue;
					}
					goto load_global_error;
				}
			}
			/* This is the un-inlined version of the code above */
			x = PyDict_GetItem(f->f_globals, w);
			if (x == NULL) {
				x = PyDict_GetItem(f->f_builtins, w);
				if (x == NULL) {
				  load_global_error:
					printf("LOAD_GLOBAL ERROR %s", ((PyStringObject *)w)->ob_sval);
					break;
				}
			}
			Py_INCREF(x);
			PUSH(x);
			break;

		case LOAD_ATTR:
			w = GETITEM(names, oparg);
			v = TOP();
			x = PyObject_GetAttr(v, w);
			Py_DECREF(v);
			SET_TOP(x);
			if (x != NULL) continue;
			break;

		case IMPORT_NAME:
			w = GETITEM(names, oparg);
			x = PyDict_GetItemString(f->f_builtins, "__import__");
			if (x == NULL) {
				printf("__import__ not found");
				break;
			}
			u = TOP();
			w = Py_BuildValue("(O)", w);
			Py_DECREF(u);
			if (w == NULL) {
				u = POP();
				x = NULL;
				break;
			}
			x = PyEval_CallObject(x, w);
			Py_DECREF(w);
			SET_TOP(x);
			if (x != NULL) continue;
			break;

		case JUMP_FORWARD:
			JUMPBY(oparg);
			goto fast_next_opcode;

		PREDICTED_WITH_ARG(JUMP_IF_FALSE);
		case JUMP_IF_FALSE:
			w = TOP();
			if (w == Py_True) {
				PREDICT(POP_TOP);
				goto fast_next_opcode;
			}
			if (w == Py_False) {
				JUMPBY(oparg);
				goto fast_next_opcode;
			}
			err = PyObject_IsTrue(w);
			if (err > 0)
				err = 0;
			else if (err == 0)
				JUMPBY(oparg);
			else
				break;
			continue;
			
		case JUMP_ABSOLUTE:
			JUMPTO(oparg);
			continue;

		case SETUP_LOOP:
			PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL());
			continue;

		case CALL_FUNCTION:
			x = call_function(&stack_pointer, oparg);
			PUSH(x);
			if (x != NULL)
				continue;
			break;
			
		case MAKE_FUNCTION:
			v = POP(); /* code object */
			x = PyFunction_New(v, f->f_globals);
			Py_DECREF(v);
			/* XXX Maybe this should be a separate opcode? */
			if (x != NULL && oparg > 0) {
				v = PyTuple_New(oparg);
				if (v == NULL) {
					Py_DECREF(x);
					x = NULL;
			break;
				}
				while (--oparg >= 0) {
					w = POP();
					PyTuple_SET_ITEM(v, oparg, w);
				}
				err = PyFunction_SetDefaults(x, v);
				Py_DECREF(v);
			}
			PUSH(x);
			break;
			
		case SET_LINENO:
			break;

		default:
			printf("opcode: %d\n", opcode);
			Py_FatalError("unknown opcode");
		} /* switch */

	  on_error:
		
		if (why == WHY_NOT) {
			if (err == 0 && x != NULL) {
					continue; /* Normal, fast path */
			}
			why = WHY_EXCEPTION;
			x = Py_None;
			err = 0;
		}

		/* End the loop if we still have an error (or return) */

		if (why != WHY_NOT)
			break;

	} /* main loop */

	if (why != WHY_YIELD) {
		/* Pop remaining stack entries -- but when yielding */
		while (!EMPTY()) {
			v = POP();
			Py_XDECREF(v);
		}
	}

	if (why != WHY_RETURN && why != WHY_YIELD)
		retval = NULL;

	/* pop frame */
	--tstate->recursion_depth;
	tstate->frame = f->f_back;

	return retval;
}}
Esempio n. 13
0
static PyObject *
eval_frame(PyFrameObject *f)
{
	LOG("> eval_frame\n");
	PyObject **stack_pointer; /* Next free slot in value stack */
	register unsigned char *next_instr;
	register int opcode=0;	/* Current opcode */
	register int oparg=0;	/* Current opcode argument, if any */
	register enum why_code why; /* Reason for block stack unwind */
	register int err;	/* Error status -- nonzero if error */
	register PyObject *x;	/* Result object -- NULL if error */
	register PyObject *v;	/* Temporary objects popped off stack */
	register PyObject *w;
	register PyObject **fastlocals, **freevars;
	PyObject *retval = NULL;	/* Return value */
	PyThreadState *tstate = PyThreadState_GET();
	PyCodeObject *co;

	unsigned char *first_instr;
	PyObject *names;
	PyObject *consts;

/* Tuple access macros */

#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i))

/* Code access macros */

#define INSTR_OFFSET()	(next_instr - first_instr)
#define NEXTOP()	(*next_instr++)
#define NEXTARG()	(next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
#define JUMPTO(x)	(next_instr = first_instr + (x))
#define JUMPBY(x)	(next_instr += (x))

/* OpCode prediction macros
	Some opcodes tend to come in pairs thus making it possible to predict
	the second code when the first is run.  For example, COMPARE_OP is often
	followed by JUMP_IF_FALSE or JUMP_IF_TRUE.  And, those opcodes are often
	followed by a POP_TOP.

	Verifying the prediction costs a single high-speed test of register
	variable against a constant.  If the pairing was good, then the
	processor has a high likelihood of making its own successful branch
	prediction which results in a nearly zero overhead transition to the
	next opcode.

	A successful prediction saves a trip through the eval-loop including
	its two unpredictable branches, the HASARG test and the switch-case.
*/

#define PREDICT(op)		if (*next_instr == op) goto PRED_##op
#define PREDICTED(op)		PRED_##op: next_instr++
#define PREDICTED_WITH_ARG(op)	PRED_##op: oparg = (next_instr[2]<<8) + \
				next_instr[1]; next_instr += 3

/* Stack manipulation macros */

#define STACK_LEVEL()	(stack_pointer - f->f_valuestack)
#define EMPTY()		(STACK_LEVEL() == 0)
#define TOP()		(stack_pointer[-1])
#define SECOND()	(stack_pointer[-2])
#define THIRD() 	(stack_pointer[-3])
#define FOURTH()	(stack_pointer[-4])
#define SET_TOP(v)	(stack_pointer[-1] = (v))
#define SET_SECOND(v)	(stack_pointer[-2] = (v))
#define SET_THIRD(v)	(stack_pointer[-3] = (v))
#define SET_FOURTH(v)	(stack_pointer[-4] = (v))
#define BASIC_STACKADJ(n)	(stack_pointer += n)
#define BASIC_PUSH(v)	(*stack_pointer++ = (v))
#define BASIC_POP()	(*--stack_pointer)

#define PUSH(v)		BASIC_PUSH(v)
#define POP()		BASIC_POP()
#define STACKADJ(n)	BASIC_STACKADJ(n)

/* Local variable macros */

#define GETLOCAL(i)	(fastlocals[i])

/* The SETLOCAL() macro must not DECREF the local variable in-place and
   then store the new value; it must copy the old value to a temporary
   value, then store the new value, and then DECREF the temporary value.
   This is because it is possible that during the DECREF the frame is
   accessed by other code (e.g. a __del__ method or gc.collect()) and the
   variable would be pointing to already-freed memory. */
#define SETLOCAL(i, value)	do { PyObject *tmp = GETLOCAL(i); \
				     GETLOCAL(i) = value; \
                                     Py_XDECREF(tmp); } while (0)

/* Start of code */

	if (f == NULL)
		return NULL;

	/* push frame */
	if (++tstate->recursion_depth > recursion_limit) {
		--tstate->recursion_depth;
		/* ERROR */
		tstate->frame = f->f_back;
		return NULL;
	}

	tstate->frame = f;

	/* tracing elided */

	co = f->f_code;
	names = co->co_names;
	consts = co->co_consts;
	fastlocals = f->f_localsplus;
	freevars = f->f_localsplus + f->f_nlocals;

	_PyCode_GETCODEPTR(co, &first_instr);

	/* An explanation is in order for the next line.

	   f->f_lasti now refers to the index of the last instruction
	   executed.  You might think this was obvious from the name, but
	   this wasn't always true before 2.3!  PyFrame_New now sets
	   f->f_lasti to -1 (i.e. the index *before* the first instruction)
	   and YIELD_VALUE doesn't fiddle with f_lasti any more.  So this
	   does work.  Promise. */
	next_instr = first_instr + f->f_lasti + 1;
	stack_pointer = f->f_stacktop;

	f->f_stacktop = NULL;	/* remains NULL unless yield suspends frame */

	why = WHY_NOT;
	err = 0;
	x = Py_None;	/* Not a reference, just anything non-NULL */
	w = NULL;

	for (;;) {

	  /* @@@ pending calls elided */

	fast_next_opcode:
		f->f_lasti = INSTR_OFFSET();

		/* Extract opcode and argument */

		opcode = NEXTOP();
		if (HAS_ARG(opcode))
			oparg = NEXTARG();

		/* Main switch on opcode */

		switch (opcode) {

		/* BEWARE!
		   It is essential that any operation that fails sets either
		   x to NULL, err to nonzero, or why to anything but WHY_NOT,
		   and that no operation that succeeds does this! */

		/* case STOP_CODE: this is an error! */

		case LOAD_CONST:
			x = GETITEM(consts, oparg);
			Py_INCREF(x);
			PUSH(x);
			goto fast_next_opcode;

		case BINARY_ADD:
			w = POP();
			v = TOP();
			if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
				/* INLINE: int + int */
				register long a, b, i;
				a = PyInt_AS_LONG(v);
				b = PyInt_AS_LONG(w);
				i = a + b;
				if ((i^a) < 0 && (i^b) < 0)
					goto slow_add;
				x = PyInt_FromLong(i);
			}
			else {
			  slow_add:
				Py_FatalError("slow add not supported.");
			}
			Py_DECREF(v);
			Py_DECREF(w);
			SET_TOP(x);
			if (x != NULL) continue;
			break;

		case PRINT_ITEM:
			v = POP();

			PyObject_Print(v);
			Py_DECREF(v);
			break;

		case PRINT_NEWLINE:
			printf("\n");
			break;

		case RETURN_VALUE:
			retval = POP();
			why = WHY_RETURN;
			break;

		default:
		  Py_FatalError("unknown opcode");
		} /* switch */

		if (why == WHY_NOT) {
			if (err == 0 && x != NULL) {
					continue; /* Normal, fast path */
			}
			why = WHY_EXCEPTION;
			x = Py_None;
			err = 0;
		}

		/* End the loop if we still have an error (or return) */

		if (why != WHY_NOT)
			break;

	} /* main loop */

	if (why != WHY_YIELD) {
		/* Pop remaining stack entries -- but when yielding */
		while (!EMPTY()) {
			v = POP();
			Py_XDECREF(v);
		}
	}

	if (why != WHY_RETURN && why != WHY_YIELD)
		retval = NULL;

	/* pop frame */
	--tstate->recursion_depth;
	tstate->frame = f->f_back;

	return retval;
}