Skip to content

Instantly share code, notes, and snippets.

@sma
Created October 7, 2009 12:15
Show Gist options
  • Save sma/204002 to your computer and use it in GitHub Desktop.
Save sma/204002 to your computer and use it in GitHub Desktop.
minimal python byte code interpreter to run the usual "fib" benchmark
package sma.python;
import java.util.HashMap;
import java.util.Map;
/**
* A minimal python byte code interpreter to run the usual "fib" benchmark.
*
* <pre>
* def fib(n):
* if n < 2:
* return 1
* return fib(n - 1) + fib(n - 2)
* </pre>
*/
public class Python {
private static final int GET_GLOBAL = 1;
private static final int CONST = 2;
private static final int CALL = 3;
private static final int PRINT = 4;
private static final int DEF = 5;
private static final int GET = 6;
private static final int LT = 7;
private static final int IF_FALSE = 8;
private static final int RETURN = 9;
private static final int SUB = 10;
private static final int ADD = 11;
static class Frame {
private final Frame parent;
private final Dict globals;
private final Dict locals;
private final Object[] opcodes;
private final Object[] stack;
private int sp;
private int ip;
Frame(Frame parent, Dict globals, Dict locals, Object[] opcodes) {
this.parent = parent;
this.globals = globals;
this.locals = locals;
this.opcodes = opcodes;
this.stack = new Object[(Integer) opcodes[0]];
this.ip = 1;
}
Frame execute() {
while (ip < opcodes.length) {
switch ((Integer) opcodes[ip++]) {
case GET_GLOBAL:
stack[sp++] = globals.get(opcodes[ip++]);
break;
case CALL: {
int ac = (Integer) opcodes[ip++];
Function f = (Function) stack[sp - ac - 1];
Dict locals = new Dict(ac);
while (--ac >= 0) {
locals.put(f.params[ac], stack[--sp]);
}
--sp; // remove function
return new Frame(this, f.globals, locals, f.opcodes);
}
case CONST:
stack[sp++] = opcodes[ip++];
break;
case DEF: {
Object name = opcodes[ip++];
Object[] params = (Object[]) opcodes[ip++];
Object[] body = (Object[]) opcodes[ip++];
locals.put(name, new Function(globals, params, body));
break;
}
case GET:
stack[sp++] = locals.get(opcodes[ip++]);
break;
case LT: {
Object b = stack[--sp];
Object a = stack[--sp];
stack[sp++] = (Integer) a < (Integer) b;
break;
}
case IF_FALSE: {
int skip = (Integer) opcodes[ip++];
if (!truish(stack[--sp])) {
ip += skip;
}
break;
}
case RETURN:
parent.stack[parent.sp++] = stack[--sp];
return parent;
case SUB: {
Object b = stack[--sp];
Object a = stack[--sp];
stack[sp++] = (Integer) a - (Integer) b;
break;
}
case ADD: {
Object b = stack[--sp];
Object a = stack[--sp];
stack[sp++] = (Integer) a + (Integer) b;
break;
}
case PRINT:
System.out.println(stack[--sp]);
break;
default:
throw new Error();
}
}
return null;
}
}
/** Returns whether an object is considered to be "true". */
private static boolean truish(Object o) {
if (o == null) {
return false;
}
if (o instanceof Boolean) {
return (Boolean) o;
}
if (o instanceof Integer) {
return ((Integer) o) != 0;
}
if (o instanceof Object[]) {
return ((Object[]) o).length > 0;
}
if (o instanceof Map) {
return ((Map) o).size() > 0;
}
if (o instanceof String) {
return ((String) o).length() > 0;
}
return true;
}
/** Implements Python dictionaries. */
private static class Dict extends HashMap<Object, Object> {
Dict(int capacity) {
super(capacity);
}
}
/** Returns a new <code>dict</code> object initialized with the given keys and values. */
public static Dict dict(Object... values) {
Dict dict = new Dict(values.length / 2);
for (int i = 0; i < values.length; i += 2) {
dict.put(values[i], values[i + 1]);
}
return dict;
}
/** Implements Python user functions. */
public static class Function {
final Dict globals;
final Object[] params;
final Object[] opcodes;
Function(Dict globals, Object[] params, Object[] opcodes) {
this.globals = globals;
this.params = params;
this.opcodes = opcodes;
}
}
/** Returns a new <code>tuple</code> object initialized with the given values. */
public static Object[] tuple(Object... values) {
return values;
}
public static final Dict globals = dict();
/** Runs a script. */
public static void run(Object... opcodes) {
Frame frame = new Frame(null, globals, globals, opcodes);
while (frame != null) {
frame = frame.execute();
}
}
public static void main(String[] args) {
/*
* execute <code>def fib(n): ...</code>
*/
Python.run(0, DEF, "fib", tuple("n"), tuple(4,
GET, "n", CONST, 2, LT, IF_FALSE, 3,
CONST, 1, RETURN,
GET_GLOBAL, "fib", GET, "n", CONST, 1, SUB, CALL, 1,
GET_GLOBAL, "fib", GET, "n", CONST, 2, SUB, CALL, 1,
ADD, RETURN));
/*
* call <code>fib(10)</code>
*/
Python.run(2, GET_GLOBAL, "fib", CONST, 30, CALL, 1, PRINT);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment