org.python.core.PyBytecode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
package org.python.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PyBytecode extends PyBaseCode {
// for debugging
private int count = 0; // total number of opcodes run so far in this code obj
private int maxCount = -1; // if -1, no cap on number of opcodes than can be run
public static boolean defaultDebug = false;
private static PyObject dis;
private static synchronized PyObject get_dis() {
if (dis == null) {
dis = __builtin__.__import__("dis");
}
return dis;
}
private static PyObject opname;
private static synchronized PyObject get_opname() {
if (opname == null) {
opname = get_dis().__getattr__("opname");
}
return opname;
}
private boolean debug;
public static void _allDebug(boolean setting) {
defaultDebug = setting;
}
public PyObject _debug(int maxCount) {
debug = maxCount > 0;
this.maxCount = maxCount;
return Py.None;
}
// end debugging
public final static int CO_MAXBLOCKS = 20; // same as in CPython
public final byte[] co_code; // widened to char to avoid signed byte issues
public final PyObject[] co_consts;
public final String[] co_names;
public final int co_stacksize; // XXX - use to convert PyStack to use PyObject[] instead of ArrayList
public final byte[] co_lnotab;
private final static int CALL_FLAG_VAR = 1;
private final static int CALL_FLAG_KW = 2;
// follows new.code's interface
public PyBytecode(int argcount, int nlocals, int stacksize, int flags,
String codestring, PyObject[] constants, String[] names, String varnames[],
String filename, String name, int firstlineno, String lnotab) {
this(argcount, nlocals, stacksize, flags, codestring,
constants, names, varnames, filename, name, firstlineno, lnotab,
null, null);
}
// XXX - intern names HERE instead of in marshal
public PyBytecode(int argcount, int nlocals, int stacksize, int flags,
String codestring, PyObject[] constants, String[] names, String varnames[],
String filename, String name, int firstlineno, String lnotab,
String[] cellvars, String[] freevars) {
debug = defaultDebug;
co_argcount = nargs = argcount;
co_varnames = varnames;
co_nlocals = nlocals; // maybe assert = varnames.length;
co_filename = filename;
co_firstlineno = firstlineno;
co_cellvars = cellvars;
co_freevars = freevars;
co_name = name;
co_flags = new CompilerFlags(flags);
varargs = co_flags.isFlagSet(CodeFlag.CO_VARARGS);
varkwargs = co_flags.isFlagSet(CodeFlag.CO_VARKEYWORDS);
co_stacksize = stacksize;
co_consts = constants;
co_names = names;
co_code = getBytes(codestring);
co_lnotab = getBytes(lnotab);
}
private static final String[] __members__ = {
"co_name", "co_argcount",
"co_varnames", "co_filename", "co_firstlineno",
"co_flags", "co_cellvars", "co_freevars", "co_nlocals",
"co_code", "co_consts", "co_names", "co_lnotab", "co_stacksize"
};
@Override
public PyObject __dir__() {
PyString members[] = new PyString[__members__.length];
for (int i = 0; i < __members__.length; i++) {
members[i] = new PyString(__members__[i]);
}
return new PyList(members);
}
private void throwReadonly(String name) {
for (int i = 0; i < __members__.length; i++) {
if (__members__[i] == name) {
throw Py.TypeError("readonly attribute");
}
}
throw Py.AttributeError(name);
}
public void __setattr__(String name, PyObject value) {
// no writable attributes
throwReadonly(name);
}
public void __delattr__(String name) {
throwReadonly(name);
}
private static PyTuple toPyStringTuple(String[] ar) {
if (ar == null) {
return Py.EmptyTuple;
}
int sz = ar.length;
PyString[] pystr = new PyString[sz];
for (int i = 0; i < sz; i++) {
pystr[i] = new PyString(ar[i]);
}
return new PyTuple(pystr);
}
public PyObject __findattr_ex__(String name) {
// have to craft co_varnames specially
if (name == "co_varnames") {
return toPyStringTuple(co_varnames);
}
if (name == "co_cellvars") {
return toPyStringTuple(co_cellvars);
}
if (name == "co_freevars") {
return toPyStringTuple(co_freevars);
}
if (name == "co_filename") {
return new PyString(co_filename);
}
if (name == "co_name") {
return new PyString(co_name);
}
if (name == "co_code") {
return new PyString(getString(co_code));
}
if (name == "co_lnotab") {
return new PyString(getString(co_lnotab));
}
if (name == "co_consts") {
return new PyTuple(co_consts);
}
if (name == "co_flags") {
return Py.newInteger(co_flags.toBits());
}
return super.__findattr_ex__(name);
}
enum Why {
NOT, /* No error */
EXCEPTION, /* Exception occurred */
RERAISE, /* Exception re-raised by 'finally' */
RETURN, /* 'return' statement */
BREAK, /* 'break' statement */
CONTINUE, /* 'continue' statement */
YIELD /* 'yield' operator */
};
// to enable why's to be stored on a PyStack
private static class PyStackWhy extends PyObject {
Why why;
PyStackWhy(Why why) {
this.why = why;
}
@Override
public String toString() {
return why.toString();
}
}
private static class PyStackException extends PyObject {
PyException exception;
PyStackException(PyException exception) {
this.exception = exception;
}
@Override
public String toString() {
return String.format("PyStackException<%s,%s,%.100s>", exception.type, exception.value, exception.traceback);
}
}
private static String stringify_blocks(PyFrame f) {
if (f.f_exits == null || f.f_lineno == 0) {
return "[]";
}
StringBuilder buf = new StringBuilder("[");
int len = f.f_lineno;
for (int i = 0; i < len; i++) {
buf.append(f.f_exits[i].toString());
if (i < len - 1) {
buf.append(", ");
}
}
buf.append("]");
return buf.toString();
}
private void print_debug(int count, int next_instr, int line, int opcode, int oparg, PyStack stack, PyFrame f) {
if (debug) {
System.err.println(co_name + " " + line + ":" +
count + "," + f.f_lasti + "> " +
get_opname().__getitem__(Py.newInteger(opcode)) +
(opcode >= Opcode.HAVE_ARGUMENT ? " " + oparg : "") +
", stack: " + stack.toString() +
", blocks: " + stringify_blocks(f));
}
}
// the following code exploits the fact that f_exits is only used by code compiled to Java bytecode;
// in their place we implement the block stack for PBC-VM, as mapped below in the comments of pushBlock
private static PyTryBlock popBlock(PyFrame f) {
return (PyTryBlock)(((PyList)f.f_exits[0]).pop());
}
private static void pushBlock(PyFrame f, PyTryBlock block) {
if (f.f_exits == null) { // allocate in the frame where they can fit! TODO consider supporting directly in the frame
f.f_exits = new PyObject[1]; // f_blockstack in CPython - a simple ArrayList might be best
f.f_exits[0] = new PyList();
}
((PyList)f.f_exits[0]).append(block);
}
private boolean blocksLeft(PyFrame f) {
if (f.f_exits != null) {
return ((PyList)f.f_exits[0]).__nonzero__();
} else {
return false;
}
}
@Override
protected PyObject interpret(PyFrame f, ThreadState ts) {
final PyStack stack = new PyStack();
int next_instr = -1;
int opcode; /* Current opcode */
int oparg = 0; /* Current opcode argument, if any */
Why why = Why.NOT;
PyObject retval = null;
LineCache lineCache = null;
int last_line = -1;
int line = 0;
// XXX - optimization opportunities
// 1. consider detaching the setting/getting of frame fields to improve performance, instead do this
// in a shadow version of the frame that we copy back to on entry/exit and downcalls
if (debug) {
System.err.println(co_name + ":" + f.f_lasti + "/" + co_code.length +
", cells:" + Arrays.toString(co_cellvars) + ", free:" + Arrays.toString(co_freevars));
int i = 0;
for (String cellvar : co_cellvars) {
System.err.println(cellvar + " = " + f.f_env[i++]);
}
for (String freevar : co_freevars) {
System.err.println(freevar + " = " + f.f_env[i++]);
}
get_dis().invoke("disassemble", this);
}
if (f.f_lasti >= co_code.length) {
throw Py.SystemError(""); // XXX - chose an appropriate error!!!
}
next_instr = f.f_lasti;
// the restore stack aspects should occur ONLY after a yield
boolean checkGeneratorInput = false;
if (f.f_savedlocals != null) {
for (int i = 0; i < f.f_savedlocals.length; i++) {
PyObject v = (PyObject) (f.f_savedlocals[i]);
stack.push(v);
}
checkGeneratorInput = true;
f.f_savedlocals = null;
}
while (!debug || (maxCount == -1 || count < maxCount)) { // XXX - replace with while(true)
if (f.tracefunc != null || debug) {
if (lineCache == null) {
lineCache = new LineCache();
if (debug) {
System.err.println("LineCache: " + lineCache.toString());
}
}
line = lineCache.getline(next_instr); // XXX - should also return the range this is valid to avoid an unnecessary bisect
if (line != last_line) {
f.setline(line);
}
}
try {
if (checkGeneratorInput) {
checkGeneratorInput = false;
Object generatorInput = f.getGeneratorInput();
if (generatorInput instanceof PyException) {
throw (PyException) generatorInput;
}
stack.push((PyObject) generatorInput);
}
opcode = getUnsigned(co_code, next_instr);
if (opcode >= Opcode.HAVE_ARGUMENT) {
next_instr += 2;
oparg = (getUnsigned(co_code, next_instr) << 8) + getUnsigned(co_code, next_instr - 1);
}
print_debug(count, next_instr, line, opcode, oparg, stack, f);
count += 1;
next_instr += 1;
f.f_lasti = next_instr;
switch (opcode) {
case Opcode.NOP:
break;
case Opcode.LOAD_FAST:
stack.push(f.getlocal(oparg));
break;
case Opcode.LOAD_CONST:
stack.push(co_consts[oparg]);
break;
case Opcode.STORE_FAST:
f.setlocal(oparg, stack.pop());
break;
case Opcode.POP_TOP:
stack.pop();
break;
case Opcode.ROT_TWO:
stack.rot2();
break;
case Opcode.ROT_THREE:
stack.rot3();
break;
case Opcode.ROT_FOUR:
stack.rot4();
break;
case Opcode.DUP_TOP:
stack.dup();
break;
case Opcode.DUP_TOPX: {
if (oparg == 2 || oparg == 3) {
stack.dup(oparg);
} else {
throw Py.RuntimeError("invalid argument to DUP_TOPX" +
" (bytecode corruption?)");
}
break;
}
case Opcode.UNARY_POSITIVE:
stack.push(stack.pop().__pos__());
break;
case Opcode.UNARY_NEGATIVE:
stack.push(stack.pop().__neg__());
break;
case Opcode.UNARY_NOT:
stack.push(stack.pop().__not__());
break;
case Opcode.UNARY_CONVERT:
stack.push(stack.pop().__repr__());
break;
case Opcode.UNARY_INVERT:
stack.push(stack.pop().__invert__());
break;
case Opcode.BINARY_POWER: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._pow(b));
break;
}
case Opcode.BINARY_MULTIPLY: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._mul(b));
break;
}
case Opcode.BINARY_DIVIDE: {
PyObject b = stack.pop();
PyObject a = stack.pop();
if (!co_flags.isFlagSet(CodeFlag.CO_FUTURE_DIVISION)) {
stack.push(a._div(b));
} else {
stack.push(a._truediv(b));
}
break;
}
case Opcode.BINARY_TRUE_DIVIDE: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._truediv(b));
break;
}
case Opcode.BINARY_FLOOR_DIVIDE: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._floordiv(b));
break;
}
case Opcode.BINARY_MODULO: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._mod(b));
break;
}
case Opcode.BINARY_ADD: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._add(b));
break;
}
case Opcode.BINARY_SUBTRACT: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._sub(b));
break;
}
case Opcode.BINARY_SUBSCR: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a.__getitem__(b));
break;
}
case Opcode.BINARY_LSHIFT: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._lshift(b));
break;
}
case Opcode.BINARY_RSHIFT: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._rshift(b));
break;
}
case Opcode.BINARY_AND: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._and(b));
break;
}
case Opcode.BINARY_XOR: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._xor(b));
break;
}
case Opcode.BINARY_OR: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._or(b));
break;
}
case Opcode.LIST_APPEND: {
PyObject b = stack.pop();
PyList a = (PyList) (stack.pop());
a.append(b);
break;
}
case Opcode.INPLACE_POWER: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._ipow(b));
break;
}
case Opcode.INPLACE_MULTIPLY: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._imul(b));
break;
}
case Opcode.INPLACE_DIVIDE: {
PyObject b = stack.pop();
PyObject a = stack.pop();
if (!co_flags.isFlagSet(CodeFlag.CO_FUTURE_DIVISION)) {
stack.push(a._idiv(b));
} else {
stack.push(a._itruediv(b));
}
break;
}
case Opcode.INPLACE_TRUE_DIVIDE: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._itruediv(b));
break;
}
case Opcode.INPLACE_FLOOR_DIVIDE: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._ifloordiv(b));
break;
}
case Opcode.INPLACE_MODULO: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._imod(b));
break;
}
case Opcode.INPLACE_ADD: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._iadd(b));
break;
}
case Opcode.INPLACE_SUBTRACT: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._isub(b));
break;
}
case Opcode.INPLACE_LSHIFT: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._ilshift(b));
break;
}
case Opcode.INPLACE_RSHIFT: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._irshift(b));
break;
}
case Opcode.INPLACE_AND: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._iand(b));
break;
}
case Opcode.INPLACE_XOR: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._ixor(b));
break;
}
case Opcode.INPLACE_OR: {
PyObject b = stack.pop();
PyObject a = stack.pop();
stack.push(a._ior(b));
break;
}
case Opcode.SLICE + 0:
case Opcode.SLICE + 1:
case Opcode.SLICE + 2:
case Opcode.SLICE + 3: {
PyObject stop = (((opcode - Opcode.SLICE) & 2) != 0) ? stack.pop() : null;
PyObject start = (((opcode - Opcode.SLICE) & 1) != 0) ? stack.pop() : null;
PyObject obj = stack.pop();
stack.push(obj.__getslice__(start, stop));
break;
}
case Opcode.STORE_SLICE + 0:
case Opcode.STORE_SLICE + 1:
case Opcode.STORE_SLICE + 2:
case Opcode.STORE_SLICE + 3: {
PyObject stop = (((opcode - Opcode.STORE_SLICE) & 2) != 0) ? stack.pop() : null;
PyObject start = (((opcode - Opcode.STORE_SLICE) & 1) != 0) ? stack.pop() : null;
PyObject obj = stack.pop();
PyObject value = stack.pop();
obj.__setslice__(start, stop, value);
break;
}
case Opcode.DELETE_SLICE + 0:
case Opcode.DELETE_SLICE + 1:
case Opcode.DELETE_SLICE + 2:
case Opcode.DELETE_SLICE + 3: {
PyObject stop = (((opcode - Opcode.DELETE_SLICE) & 2) != 0) ? stack.pop() : null;
PyObject start = (((opcode - Opcode.DELETE_SLICE) & 1) != 0) ? stack.pop() : null;
PyObject obj = stack.pop();
obj.__delslice__(start, stop);
break;
}
case Opcode.STORE_SUBSCR: {
PyObject key = stack.pop();
PyObject obj = stack.pop();
PyObject value = stack.pop();
obj.__setitem__(key, value);
break;
}
case Opcode.DELETE_SUBSCR: {
PyObject key = stack.pop();
PyObject obj = stack.pop();
obj.__delitem__(key);
break;
}
case Opcode.PRINT_EXPR:
PySystemState.displayhook(stack.pop());
break;
case Opcode.PRINT_ITEM_TO:
Py.printComma(stack.pop(), stack.pop());
break;
case Opcode.PRINT_ITEM:
Py.printComma(stack.pop());
break;
case Opcode.PRINT_NEWLINE_TO:
Py.printlnv(stack.pop());
break;
case Opcode.PRINT_NEWLINE:
Py.println();
break;
case Opcode.RAISE_VARARGS:
switch (oparg) {
case 3: {
PyTraceback tb = (PyTraceback) (stack.pop());
PyObject value = stack.pop();
PyObject type = stack.pop();
throw PyException.doRaise(type, value, tb);
}
case 2: {
PyObject value = stack.pop();
PyObject type = stack.pop();
throw PyException.doRaise(type, value, null);
}
case 1: {
PyObject type = stack.pop();
throw PyException.doRaise(type, null, null);
}
case 0:
throw PyException.doRaise(null, null, null);
default:
throw Py.SystemError("bad RAISE_VARARGS oparg");
}
case Opcode.LOAD_LOCALS:
stack.push(f.f_locals);
break;
case Opcode.RETURN_VALUE:
retval = stack.pop();
why = Why.RETURN;
break;
case Opcode.YIELD_VALUE:
retval = stack.pop();
why = Why.YIELD;
break;
case Opcode.EXEC_STMT: {
PyObject locals = stack.pop();
PyObject globals = stack.pop();
PyObject code = stack.pop();
Py.exec(code, globals == Py.None ? null : globals, locals == Py.None ? null : locals);
break;
}
case Opcode.POP_BLOCK: {
PyTryBlock b = popBlock(f);
while (stack.size() > b.b_level) {
stack.pop();
}
break;
}
case Opcode.END_FINALLY: {
PyObject v = stack.pop();
if (v instanceof PyStackWhy) {
why = ((PyStackWhy) v).why;
assert (why != Why.YIELD);
if (why == Why.RETURN || why == Why.CONTINUE) {
retval = stack.pop();
}
} else if (v instanceof PyStackException) {
ts.exception = ((PyStackException) v).exception;
why = Why.RERAISE;
} else if (v instanceof PyString) {
why = Why.RERAISE;
} else if (v != Py.None) {
throw Py.SystemError("'finally' pops bad exception");
}
break;
}
case Opcode.BUILD_CLASS: {
PyObject methods = stack.pop();
PyObject bases[] = ((PySequenceList) (stack.pop())).getArray();
String name = stack.pop().toString();
stack.push(Py.makeClass(name, bases, methods));
break;
}
case Opcode.STORE_NAME:
f.setlocal(co_names[oparg], stack.pop());
break;
case Opcode.DELETE_NAME:
f.dellocal(co_names[oparg]);
break;
case Opcode.UNPACK_SEQUENCE:
unpack_iterable(oparg, stack);
break;
case Opcode.STORE_ATTR: {
PyObject obj = stack.pop();
PyObject v = stack.pop();
obj.__setattr__(co_names[oparg], v);
break;
}
case Opcode.DELETE_ATTR:
stack.pop().__delattr__(co_names[oparg]);
break;
case Opcode.STORE_GLOBAL:
f.setglobal(co_names[oparg], stack.pop());
break;
case Opcode.DELETE_GLOBAL:
f.delglobal(co_names[oparg]);
break;
case Opcode.LOAD_NAME:
stack.push(f.getname(co_names[oparg]));
break;
case Opcode.LOAD_GLOBAL:
stack.push(f.getglobal(co_names[oparg]));
break;
case Opcode.DELETE_FAST:
f.dellocal(oparg);
break;
case Opcode.LOAD_CLOSURE: {
PyCell cell = (PyCell) (f.getclosure(oparg));
if (cell.ob_ref == null) {
String name;
if (oparg >= co_cellvars.length) {
name = co_freevars[oparg - co_cellvars.length];
} else {
name = co_cellvars[oparg];
}
// XXX - consider some efficient lookup mechanism, like a hash :),
// at least if co_varnames is much greater than say a certain
// size (but i would think, it's not going to happen in real code. profile?)
if (f.f_fastlocals != null) {
int i = 0;
boolean matched = false;
for (String match : co_varnames) {
if (match.equals(name)) {
matched = true;
break;
}
i++;
}
if (matched) {
cell.ob_ref = f.f_fastlocals[i];
}
} else {
cell.ob_ref = f.f_locals.__finditem__(name);
}
}
stack.push(cell);
break;
}
case Opcode.LOAD_DEREF: {
// common code from LOAD_CLOSURE
PyCell cell = (PyCell) (f.getclosure(oparg));
if (cell.ob_ref == null) {
String name;
if (oparg >= co_cellvars.length) {
name = co_freevars[oparg - co_cellvars.length];
} else {
name = co_cellvars[oparg];
}
// XXX - consider some efficient lookup mechanism, like a hash :),
// at least if co_varnames is much greater than say a certain
// size (but i would think, it's not going to happen in real code. profile?)
if (f.f_fastlocals != null) {
int i = 0;
boolean matched = false;
for (String match : co_varnames) {
if (match.equals(name)) {
matched = true;
break;
}
i++;
}
if (matched) {
cell.ob_ref = f.f_fastlocals[i];
}
} else {
cell.ob_ref = f.f_locals.__finditem__(name);
}
}
stack.push(cell.ob_ref);
break;
}
case Opcode.STORE_DEREF:
f.setderef(oparg, stack.pop());
break;
case Opcode.BUILD_TUPLE:
stack.push(new PyTuple(stack.popN(oparg)));
break;
case Opcode.BUILD_LIST:
stack.push(new PyList(stack.popN(oparg)));
break;
case Opcode.BUILD_MAP:
stack.push(new PyDictionary());
break;
case Opcode.LOAD_ATTR: {
String name = co_names[oparg];
stack.push(stack.pop().__getattr__(name));
break;
}
case Opcode.COMPARE_OP: {
PyObject b = stack.pop();
PyObject a = stack.pop();
switch (oparg) {
case Opcode.PyCmp_LT:
stack.push(a._lt(b));
break;
case Opcode.PyCmp_LE:
stack.push(a._le(b));
break;
case Opcode.PyCmp_EQ:
stack.push(a._eq(b));
break;
case Opcode.PyCmp_NE:
stack.push(a._ne(b));
break;
case Opcode.PyCmp_GT:
stack.push(a._gt(b));
break;
case Opcode.PyCmp_GE:
stack.push(a._ge(b));
break;
case Opcode.PyCmp_IN:
stack.push(a._in(b));
break;
case Opcode.PyCmp_NOT_IN:
stack.push(a._notin(b));
break;
case Opcode.PyCmp_IS:
stack.push(a._is(b));
break;
case Opcode.PyCmp_IS_NOT:
stack.push(a._isnot(b));
break;
case Opcode.PyCmp_EXC_MATCH:
if (a instanceof PyStackException) {
PyException pye = ((PyStackException) a).exception;
stack.push(Py.newBoolean(pye.match(b)));
} else {
stack.push(Py.newBoolean(new PyException(a).match(b)));
}
break;
}
break;
}
case Opcode.IMPORT_NAME: {
PyObject __import__ = f.f_builtins.__finditem__("__import__");
if (__import__ == null) {
throw Py.ImportError("__import__ not found");
}
PyString name = Py.newString(co_names[oparg]);
PyObject fromlist = stack.pop();
PyObject level = stack.pop();
if (level.asInt() != -1) {
stack.push(__import__.__call__(new PyObject[]{name, f.f_globals, f.f_locals, fromlist, level}));
} else {
stack.push(__import__.__call__(new PyObject[]{name, f.f_globals, f.f_locals, fromlist}));
}
break;
}
case Opcode.IMPORT_STAR: {
PyObject module = stack.pop();
imp.importAll(module, f);
break;
}
case Opcode.IMPORT_FROM:
String name = co_names[oparg];
try {
stack.push(stack.top().__getattr__(name));
} catch (PyException pye) {
if (pye.match(Py.AttributeError)) {
throw Py.ImportError(String.format("cannot import name %.230s", name));
} else {
throw pye;
}
}
break;
case Opcode.JUMP_FORWARD:
next_instr += oparg;
break;
case Opcode.JUMP_IF_FALSE:
if (!stack.top().__nonzero__()) {
next_instr += oparg;
}
break;
case Opcode.JUMP_IF_TRUE:
if (stack.top().__nonzero__()) {
next_instr += oparg;
}
break;
case Opcode.JUMP_ABSOLUTE:
next_instr = oparg;
break;
case Opcode.GET_ITER: {
PyObject it = stack.top().__iter__();
if (it != null) {
stack.set_top(it);
}
break;
}
case Opcode.FOR_ITER: {
PyObject it = stack.pop();
try {
PyObject x = it.__iternext__();
if (x != null) {
stack.push(it);
stack.push(x);
break;
}
} catch (PyException pye) {
if (!pye.match(Py.StopIteration)) {
throw pye;
}
}
next_instr += oparg;
break;
}
case Opcode.BREAK_LOOP:
why = Why.BREAK;
break;
case Opcode.CONTINUE_LOOP:
retval = Py.newInteger(oparg);
if (retval.__nonzero__()) {
why = Why.CONTINUE;
}
break;
case Opcode.SETUP_LOOP:
case Opcode.SETUP_EXCEPT:
case Opcode.SETUP_FINALLY:
pushBlock(f, new PyTryBlock(opcode, next_instr + oparg, stack.size()));
break;
case Opcode.WITH_CLEANUP: {
/* TOP is the context.__exit__ bound method.
Below that are 1-3 values indicating how/why
we entered the finally clause:
- SECOND = None
- (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval
- SECOND = WHY_*; no retval below it
- (SECOND, THIRD, FOURTH) = exc_info()
In the last case, we must call
TOP(SECOND, THIRD, FOURTH)
otherwise we must call
TOP(None, None, None)
In addition, if the stack represents an exception,
*and* the function call returns a 'true' value, we
"zap" this information, to prevent END_FINALLY from
re-raising the exception. (But non-local gotos
should still be resumed.)
*/
PyObject exit = stack.top();
PyObject u = stack.top(2);
PyObject v;
PyObject w;
if (u == Py.None || u instanceof PyStackWhy) {
u = v = w = Py.None;
} else {
v = stack.top(3);
w = stack.top(4);
}
PyObject x = null;
if (u instanceof PyStackException) {
PyException exc = ((PyStackException) u).exception;
x = exit.__call__(exc.type, exc.value, exc.traceback);
} else {
x = exit.__call__(u, v, w);
}
if (u != Py.None && x != null && x.__nonzero__()) {
stack.popN(4); // XXX - consider stack.stackadj op
stack.push(Py.None);
} else {
stack.pop(); // this should be popping off a block
}
break;
}
case Opcode.CALL_FUNCTION: {
int na = oparg & 0xff;
int nk = (oparg >> 8) & 0xff;
if (nk == 0) {
call_function(na, stack);
} else {
call_function(na, nk, stack);
}
break;
}
case Opcode.CALL_FUNCTION_VAR:
case Opcode.CALL_FUNCTION_KW:
case Opcode.CALL_FUNCTION_VAR_KW: {
int na = oparg & 0xff;
int nk = (oparg >> 8) & 0xff;
int flags = (opcode - Opcode.CALL_FUNCTION) & 3;
call_function(na, nk,
(flags & CALL_FLAG_VAR) != 0,
(flags & CALL_FLAG_KW) != 0,
stack);
break;
}
case Opcode.MAKE_FUNCTION: {
PyCode code = (PyCode) stack.pop();
PyObject[] defaults = stack.popN(oparg);
PyObject doc = null;
if (code instanceof PyBytecode && ((PyBytecode) code).co_consts.length > 0) {
doc = ((PyBytecode) code).co_consts[0];
}
PyFunction func = new PyFunction(f.f_globals, defaults, code, doc);
stack.push(func);
break;
}
case Opcode.MAKE_CLOSURE: {
PyCode code = (PyCode) stack.pop();
PyObject[] closure_cells = ((PySequenceList) (stack.pop())).getArray();
PyObject[] defaults = stack.popN(oparg);
PyObject doc = null;
if (code instanceof PyBytecode && ((PyBytecode) code).co_consts.length > 0) {
doc = ((PyBytecode) code).co_consts[0];
}
PyFunction func = new PyFunction(f.f_globals, defaults, code, doc, closure_cells);
stack.push(func);
break;
}
case Opcode.BUILD_SLICE: {
PyObject step = oparg == 3 ? stack.pop() : null;
PyObject stop = stack.pop();
PyObject start = stack.pop();
stack.push(new PySlice(start, stop, step));
break;
}
case Opcode.EXTENDED_ARG:
opcode = getUnsigned(co_code, next_instr++);
next_instr += 2;
oparg = oparg << 16 | ((getUnsigned(co_code, next_instr) << 8) + getUnsigned(co_code, next_instr - 1));
break;
default:
Py.print(Py.getSystemState().stderr,
Py.newString(
String.format("XXX lineno: %d, opcode: %d\n",
f.f_lasti, opcode)));
throw Py.SystemError("unknown opcode");
} // end switch
} // end try
catch (Throwable t) {
PyException pye = Py.setException(t, f);
why = Why.EXCEPTION;
ts.exception = pye;
if (debug) {
System.err.println("Caught exception:" + pye);
}
}
if (why == Why.YIELD) {
break;
}
// do some trace handling here, but for now just convert to EXCEPTION
if (why == Why.RERAISE) {
why = Why.EXCEPTION;
}
while (why != Why.NOT && blocksLeft(f)) {
PyTryBlock b = popBlock(f);
if (debug) {
System.err.println("Processing block: " + b);
}
assert (why != Why.YIELD);
if (b.b_type == Opcode.SETUP_LOOP && why == Why.CONTINUE) {
pushBlock(f, b);
why = Why.NOT;
next_instr = retval.asInt();
break;
}
while (stack.size() > b.b_level) {
stack.pop();
}
if (b.b_type == Opcode.SETUP_LOOP && why == Why.BREAK) {
why = Why.NOT;
next_instr = b.b_handler;
break;
}
if (b.b_type == Opcode.SETUP_FINALLY || (b.b_type == Opcode.SETUP_EXCEPT && why == Why.EXCEPTION)) {
if (why == Why.EXCEPTION) {
PyException exc = ts.exception;
if (b.b_type == Opcode.SETUP_EXCEPT) {
exc.normalize();
}
stack.push(exc.traceback);
stack.push(exc.value);
stack.push(new PyStackException(exc)); // instead of stack.push(exc.type), like CPython
} else {
if (why == Why.RETURN || why == Why.CONTINUE) {
stack.push(retval);
}
stack.push(new PyStackWhy(why));
}
why = Why.NOT;
next_instr = b.b_handler;
break;
}
} // unwind block stack
if (why != Why.NOT) {
break;
}
} // end-while of the instruction loop
if (why != Why.YIELD) {
while (stack.size() > 0) {
stack.pop();
}
if (why != Why.RETURN) {
retval = Py.None;
}
} else {
// store the stack in the frame for reentry from the yield;
f.f_savedlocals = stack.popN(stack.size());
}
f.f_lasti = next_instr; // need to update on function entry, etc
if (debug) {
System.err.println(count + "," + f.f_lasti + "> Returning from " + why + ": " + retval +
", stack: " + stack.toString() +
", blocks: " + stringify_blocks(f));
}
if (why == why.EXCEPTION) {
throw ts.exception;
}
if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR) && why == Why.RETURN && retval == Py.None) {
f.f_lasti = -1;
}
return retval;
}
private static void call_function(int na, PyStack stack) {
switch (na) {
case 0: {
PyObject callable = stack.pop();
stack.push(callable.__call__());
break;
}
case 1: {
PyObject arg = stack.pop();
PyObject callable = stack.pop();
stack.push(callable.__call__(arg));
break;
}
case 2: {
PyObject arg1 = stack.pop();
PyObject arg0 = stack.pop();
PyObject callable = stack.pop();
stack.push(callable.__call__(arg0, arg1));
break;
}
case 3: {
PyObject arg2 = stack.pop();
PyObject arg1 = stack.pop();
PyObject arg0 = stack.pop();
PyObject callable = stack.pop();
stack.push(callable.__call__(arg0, arg1, arg2));
break;
}
case 4: {
PyObject arg3 = stack.pop();
PyObject arg2 = stack.pop();
PyObject arg1 = stack.pop();
PyObject arg0 = stack.pop();
PyObject callable = stack.pop();
stack.push(callable.__call__(arg0, arg1, arg2, arg3));
break;
}
default: {
PyObject args[] = stack.popN(na);
PyObject callable = stack.pop();
stack.push(callable.__call__(args));
}
}
}
private static void call_function(int na, int nk, PyStack stack) {
int n = na + nk * 2;
PyObject params[] = stack.popN(n);
PyObject callable = stack.pop();
PyObject args[] = new PyObject[na + nk];
String keywords[] = new String[nk];
int i;
for (i = 0; i < na; i++) {
args[i] = params[i];
}
for (int j = 0; i < n; i += 2, j++) {
keywords[j] = params[i].toString();
args[na + j] = params[i + 1];
}
stack.push(callable.__call__(args, keywords));
}
private static void call_function(int na, int nk, boolean var, boolean kw, PyStack stack) {
int n = na + nk * 2;
PyObject kwargs = kw ? stack.pop() : null;
PyObject starargs = var ? stack.pop() : null;
PyObject params[] = stack.popN(n);
PyObject callable = stack.pop();
PyObject args[] = new PyObject[na + nk];
String keywords[] = new String[nk];
int i;
for (i = 0; i < na; i++) {
args[i] = params[i];
}
for (int j = 0; i < n; i += 2, j++) {
keywords[j] = params[i].toString();
args[na + j] = params[i + 1];
}
stack.push(callable._callextra(args, keywords, starargs, kwargs));
}
private static void unpack_iterable(int oparg, PyStack stack) {
PyObject v = stack.pop();
int i = oparg;
PyObject items[] = new PyObject[oparg];
for (PyObject item : v.asIterable()) {
if (i <= 0) {
throw Py.ValueError("too many values to unpack");
}
i--;
items[i] = item;
}
if (i > 0) {
throw Py.ValueError(String.format("need more than %d value%s to unpack",
i, i == 1 ? "" : "s"));
}
for (i = 0; i < oparg; i++) {
stack.push(items[i]);
}
}
// XXX - perhaps add support for max stack size (presumably from co_stacksize)
// and capacity hints
private static class PyStack {
final List stack;
PyStack() {
stack = new ArrayList();
}
PyObject top() {
return stack.get(stack.size() - 1);
}
PyObject top(int n) {
return stack.get(stack.size() - n);
}
PyObject pop() {
return stack.remove(stack.size() - 1);
}
void push(PyObject v) {
stack.add(v);
}
void set_top(PyObject v) {
stack.set(stack.size() - 1, v);
}
void dup() {
stack.add(top());
}
void dup(int n) {
int length = stack.size();
for (int i = n; i > 0; i--) {
stack.add(stack.get(length - i));
}
}
PyObject[] popN(int n) {
int end = stack.size(); // exclusive
PyObject ret[] = new PyObject[n];
List lastN = stack.subList(end - n, end);
lastN.toArray(ret);
lastN.clear();
return ret;
}
void rot2() {
int length = stack.size();
PyObject v = stack.get(length - 1);
PyObject w = stack.get(length - 2);
stack.set(length - 1, w);
stack.set(length - 2, v);
}
void rot3() {
int length = stack.size();
PyObject v = stack.get(length - 1);
PyObject w = stack.get(length - 2);
PyObject x = stack.get(length - 3);
stack.set(length - 1, w);
stack.set(length - 2, x);
stack.set(length - 3, v);
}
void rot4() {
int length = stack.size();
PyObject u = stack.get(length - 1);
PyObject v = stack.get(length - 2);
PyObject w = stack.get(length - 3);
PyObject x = stack.get(length - 4);
stack.set(length - 1, v);
stack.set(length - 2, w);
stack.set(length - 3, x);
stack.set(length - 4, u);
}
int size() {
return stack.size();
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
int size = stack.size();
int N = size > 4 ? 4 : size;
buffer.append("[");
for (int i = 0; i < N; i++) {
if (i > 0) {
buffer.append(", ");
}
PyObject item = stack.get(size - (i + 1));
buffer.append(upto(item.__repr__().toString()));
}
if (N < size) {
buffer.append(String.format(", %d more...", size - N));
}
buffer.append("]");
return buffer.toString();
}
private String upto(String x) {
return upto(x, 100);
}
private String upto(String x, int n) {
x = x.replace('\n', '|');
if (x.length() > n) {
StringBuilder item = new StringBuilder(x.substring(0, n));
item.append("...");
return item.toString();
} else {
return x;
}
}
}
private static class PyTryBlock extends PyObject { // purely to sit on top of the existing PyFrame in f_exits!!!
int b_type; /* what kind of block this is */
int b_handler; /* where to jump to find handler */
int b_level; /* value stack level to pop to */
PyTryBlock(int type, int handler, int level) {
b_type = type;
b_handler = handler;
b_level = level;
}
@Override
public String toString() {
return "<" + get_opname().__getitem__(Py.newInteger(b_type)) + "," +
b_handler + "," + b_level + ">";
}
}
@Override
protected int getline(PyFrame f) {
int addrq = f.f_lasti;
int size = co_lnotab.length / 2;
int p = 0;
int line = co_firstlineno;
int addr = 0;
while (--size >= 0) {
addr += getUnsigned(co_lnotab, p++);
if (addr > addrq) {
break;
}
line += getUnsigned(co_lnotab, p++);
}
return line;
}
private class LineCache {
private class Pair {
private final int addr;
private final int line;
private Pair(int a, int b) {
this.addr = a;
this.line = b;
}
public String toString() {
return "(" + addr + "," + line + ")";
}
}
List addr_breakpoints = new ArrayList();
List lines = new ArrayList(); // length should be one more than addr_breakpoints
private LineCache() { // based on dis.findlinestarts
int size = co_lnotab.length / 2;
int p = 0;
int lastline = -1;
int line = co_firstlineno;
int addr = 0;
while (--size >= 0) {
int byte_incr = getUnsigned(co_lnotab, p++);
int line_incr = getUnsigned(co_lnotab, p++);
if (byte_incr > 0) {
if (line != lastline) {
addr_breakpoints.add(addr);
lines.add(line);
lastline = line;
}
addr += byte_incr;
}
line += line_incr;
}
if (line != lastline) {
lines.add(line);
}
}
private int getline(int addrq) { // bisect_right to the lineno
int lo = 0;
int hi = addr_breakpoints.size();
while (lo < hi) {
int mid = (lo + hi) / 2;
if (addrq < addr_breakpoints.get(mid)) {
hi = mid;
} else {
lo = mid + 1;
}
}
return lines.get(lo);
}
@Override
public String toString() {
return addr_breakpoints.toString() + ";" + lines.toString();
}
}
// Utility functions to enable storage of unsigned bytes in co_code, co_lnotab byte[] arrays
private static char getUnsigned(byte[] x, int i) {
byte b = x[i];
if (b < 0) {
return (char) (b + 256);
} else {
return (char) b;
}
}
private static String getString(byte[] x) {
StringBuilder buffer = new StringBuilder(x.length);
for (int i = 0; i < x.length; i++) {
buffer.append(getUnsigned(x, i));
}
return buffer.toString();
}
private static byte[] getBytes(String s) {
int len = s.length();
byte[] x = new byte[len];
for (int i = 0; i < len; i++) {
x[i] = (byte) (s.charAt(i) & 0xFF);
}
return x;
}
}