Skip to content

Commit ef8ace3

Browse files
committed
Charles G. Waldman <cgw@fnal.gov>:
Add the EXTENDED_ARG opcode to the virtual machine, allowing 32-bit arguments to opcodes instead of being forced to stick to the 16-bit limit. This is especially useful for machine-generated code, which can be too long for the SET_LINENO parameter to fit into 16 bits. This closes the implementation portion of SourceForge patch #100893.
1 parent e266e42 commit ef8ace3

File tree

6 files changed

+56
-6
lines changed

6 files changed

+56
-6
lines changed

Include/node.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ extern "C" {
1919
typedef struct _node {
2020
short n_type;
2121
char *n_str;
22-
short n_lineno;
23-
short n_nchildren;
22+
int n_lineno;
23+
int n_nchildren;
2424
struct _node *n_child;
2525
} node;
2626

Include/opcode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
130130
#define CALL_FUNCTION_KW 141 /* #args + (#kwargs<<8) */
131131
#define CALL_FUNCTION_VAR_KW 142 /* #args + (#kwargs<<8) */
132132

133+
/* Support for opargs more than 16 bits long */
134+
#define EXTENDED_ARG 143
135+
133136
/* Comparison operator codes (argument to COMPARE_OP) */
134137
enum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD};
135138

Lib/dis.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def disassemble(co, lasti=-1):
5656
labels = findlabels(code)
5757
n = len(code)
5858
i = 0
59+
extended_arg = 0
5960
while i < n:
6061
c = code[i]
6162
op = ord(c)
@@ -68,8 +69,11 @@ def disassemble(co, lasti=-1):
6869
print string.ljust(opname[op], 20),
6970
i = i+1
7071
if op >= HAVE_ARGUMENT:
71-
oparg = ord(code[i]) + ord(code[i+1])*256
72+
oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
73+
extended_arg = 0
7274
i = i+2
75+
if op == EXTENDED_ARG:
76+
extended_arg = oparg*65536L
7377
print string.rjust(`oparg`, 5),
7478
if op in hasconst:
7579
print '(' + `co.co_consts[oparg]` + ')',
@@ -258,6 +262,8 @@ def jabs_op(name, op):
258262
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
259263
def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
260264

265+
def_op('EXTENDED_ARG', 143)
266+
EXTENDED_ARG = 143
261267

262268
def _test():
263269
"""Simple test program to disassemble a file."""

Parser/node.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ See the file "Misc/COPYRIGHT" for information on usage and
88
redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
99
******************************************************************/
1010

11+
#ifdef HAVE_LIMITS_H
1112
#include <limits.h>
13+
#endif
14+
#ifndef INT_MAX
15+
#define INT_MAX 2147483647
16+
#endif
1217

1318
/* Parse tree node implementation */
1419

@@ -39,7 +44,7 @@ PyNode_AddChild(register node *n1, int type, char *str, int lineno)
3944
register int nch = n1->n_nchildren;
4045
register int nch1 = nch+1;
4146
register node *n;
42-
if (nch == SHRT_MAX || nch < 0)
47+
if (nch == INT_MAX || nch < 0)
4348
return E_OVERFLOW;
4449
if (XXXROUNDUP(nch) < nch1) {
4550
n = n1->n_child;

Python/ceval.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
613613
opcode = NEXTOP();
614614
if (HAS_ARG(opcode))
615615
oparg = NEXTARG();
616+
dispatch_opcode:
616617
#ifdef DYNAMIC_EXECUTION_PROFILE
617618
#ifdef DXPAIRS
618619
dxpairs[lastopcode][opcode]++;
@@ -1750,6 +1751,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
17501751
if (x != NULL) continue;
17511752
break;
17521753

1754+
case EXTENDED_ARG:
1755+
opcode = NEXTOP();
1756+
oparg = oparg<<16 | NEXTARG();
1757+
goto dispatch_opcode;
1758+
break;
17531759

17541760
default:
17551761
fprintf(stderr,

Python/compile.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
3636
#ifdef HAVE_LIMITS_H
3737
#include <limits.h>
3838
#endif
39+
#ifndef INT_MAX
40+
#define INT_MAX 2147483647
41+
#endif
3942

4043
/* Three symbols from graminit.h are also defined in Python.h, with
4144
Py_ prefixes to their names. Python.h can't include graminit.h
@@ -572,11 +575,17 @@ com_set_lineno(struct compiling *c, int lineno)
572575
static void
573576
com_addoparg(struct compiling *c, int op, int arg)
574577
{
578+
int extended_arg = arg >> 16;
575579
if (op == SET_LINENO) {
576580
com_set_lineno(c, arg);
577581
if (Py_OptimizeFlag)
578582
return;
579583
}
584+
if (extended_arg){
585+
com_addbyte(c, EXTENDED_ARG);
586+
com_addint(c, extended_arg);
587+
arg &= 0xffff;
588+
}
580589
com_addbyte(c, op);
581590
com_addint(c, arg);
582591
}
@@ -606,7 +615,14 @@ com_backpatch(struct compiling *c, int anchor)
606615
prev = code[anchor] + (code[anchor+1] << 8);
607616
dist = target - (anchor+2);
608617
code[anchor] = dist & 0xff;
609-
code[anchor+1] = dist >> 8;
618+
dist >>= 8;
619+
code[anchor+1] = dist;
620+
dist >>= 8;
621+
if (dist) {
622+
com_error(c, PyExc_SystemError,
623+
"com_backpatch: offset too large");
624+
break;
625+
}
610626
if (!prev)
611627
break;
612628
anchor -= prev;
@@ -3364,6 +3380,7 @@ optimize(struct compiling *c)
33643380
break;
33653381
if (HAS_ARG(opcode))
33663382
oparg = NEXTARG();
3383+
dispatch_opcode1:
33673384
switch (opcode) {
33683385
case STORE_NAME:
33693386
case DELETE_NAME:
@@ -3374,6 +3391,11 @@ optimize(struct compiling *c)
33743391
case EXEC_STMT:
33753392
c->c_flags &= ~CO_OPTIMIZED;
33763393
break;
3394+
case EXTENDED_ARG:
3395+
opcode = NEXTOP();
3396+
oparg = oparg<<16 | NEXTARG();
3397+
goto dispatch_opcode1;
3398+
break;
33773399
}
33783400
}
33793401

@@ -3389,6 +3411,7 @@ optimize(struct compiling *c)
33893411
break;
33903412
if (HAS_ARG(opcode))
33913413
oparg = NEXTARG();
3414+
dispatch_opcode2:
33923415
if (opcode == LOAD_NAME ||
33933416
opcode == STORE_NAME ||
33943417
opcode == DELETE_NAME) {
@@ -3403,13 +3426,20 @@ optimize(struct compiling *c)
34033426
continue;
34043427
}
34053428
i = PyInt_AsLong(v);
3429+
if (i >> 16) /* too big for 2 bytes */
3430+
continue;
34063431
switch (opcode) {
34073432
case LOAD_NAME: cur_instr[0] = LOAD_FAST; break;
34083433
case STORE_NAME: cur_instr[0] = STORE_FAST; break;
34093434
case DELETE_NAME: cur_instr[0] = DELETE_FAST; break;
34103435
}
34113436
cur_instr[1] = i & 0xff;
3412-
cur_instr[2] = (i>>8) & 0xff;
3437+
cur_instr[2] = i >> 8;
3438+
}
3439+
if (opcode == EXTENDED_ARG) {
3440+
opcode = NEXTOP();
3441+
oparg = oparg<<16 | NEXTARG();
3442+
goto dispatch_opcode2;
34133443
}
34143444
}
34153445

0 commit comments

Comments
 (0)