Created
October 7, 2009 12:15
-
-
Save sma/204002 to your computer and use it in GitHub Desktop.
minimal python byte code interpreter to run the usual "fib" benchmark
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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