Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Migrating speedy python stuff out of the python source tree and

hopefully into an independent module.
  • Loading branch information...
commit 012fcd6b7d47a792b4b8e753fac34cdc7de5fb80 0 parents
@rjpower authored
284 ez_setup.py
@@ -0,0 +1,284 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c11"
+DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+ 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+ 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+ 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+ 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+ 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+ 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+ 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+ 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+ 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+ 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+ 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
+ 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
+ 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
+ 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
+ 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
+ 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
+ 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
+ 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
+ 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+ 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+ 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+ 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+ 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+ 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+ 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+ 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+ 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+ 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+ 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+ 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+ 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+ 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+ 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+ 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+ 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+ 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+ 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+ 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+ 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
+ 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
+ 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
+ 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
+}
+
+import sys, os
+try: from hashlib import md5
+except ImportError: from md5 import md5
+
+def _validate_md5(egg_name, data):
+ if egg_name in md5_data:
+ digest = md5(data).hexdigest()
+ if digest != md5_data[egg_name]:
+ print >>sys.stderr, (
+ "md5 validation of %s failed! (Possible download problem?)"
+ % egg_name
+ )
+ sys.exit(2)
+ return data
+
+def use_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ download_delay=15
+):
+ """Automatically find/download setuptools and make it available on sys.path
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end with
+ a '/'). `to_dir` is the directory where setuptools will be downloaded, if
+ it is not already available. If `download_delay` is specified, it should
+ be the number of seconds that will be paused before initiating a download,
+ should one be required. If an older version of setuptools is installed,
+ this routine will print a message to ``sys.stderr`` and raise SystemExit in
+ an attempt to abort the calling script.
+ """
+ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+ def do_download():
+ egg = download_setuptools(version, download_base, to_dir, download_delay)
+ sys.path.insert(0, egg)
+ import setuptools; setuptools.bootstrap_install_from = egg
+ try:
+ import pkg_resources
+ except ImportError:
+ return do_download()
+ try:
+ pkg_resources.require("setuptools>="+version); return
+ except pkg_resources.VersionConflict, e:
+ if was_imported:
+ print >>sys.stderr, (
+ "The required version of setuptools (>=%s) is not available, and\n"
+ "can't be installed while this script is running. Please install\n"
+ " a more recent version first, using 'easy_install -U setuptools'."
+ "\n\n(Currently using %r)"
+ ) % (version, e.args[0])
+ sys.exit(2)
+ except pkg_resources.DistributionNotFound:
+ pass
+
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return do_download()
+
+def download_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ delay = 15
+):
+ """Download setuptools from a specified location and return its filename
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download attempt.
+ """
+ import urllib2, shutil
+ egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+ url = download_base + egg_name
+ saveto = os.path.join(to_dir, egg_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ from distutils import log
+ if delay:
+ log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help). I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+ %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+ version, download_base, delay, url
+ ); from time import sleep; sleep(delay)
+ log.warn("Downloading %s", url)
+ src = urllib2.urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = _validate_md5(egg_name, src.read())
+ dst = open(saveto,"wb"); dst.write(data)
+ finally:
+ if src: src.close()
+ if dst: dst.close()
+ return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ try:
+ import setuptools
+ except ImportError:
+ egg = None
+ try:
+ egg = download_setuptools(version, delay=0)
+ sys.path.insert(0,egg)
+ from setuptools.command.easy_install import main
+ return main(list(argv)+[egg]) # we're done here
+ finally:
+ if egg and os.path.exists(egg):
+ os.unlink(egg)
+ else:
+ if setuptools.__version__ == '0.0.1':
+ print >>sys.stderr, (
+ "You have an obsolete version of setuptools installed. Please\n"
+ "remove it from your system entirely before rerunning this script."
+ )
+ sys.exit(2)
+
+ req = "setuptools>="+version
+ import pkg_resources
+ try:
+ pkg_resources.require(req)
+ except pkg_resources.VersionConflict:
+ try:
+ from setuptools.command.easy_install import main
+ except ImportError:
+ from easy_install import main
+ main(list(argv)+[download_setuptools(delay=0)])
+ sys.exit(0) # try to force an exit
+ else:
+ if argv:
+ from setuptools.command.easy_install import main
+ main(argv)
+ else:
+ print "Setuptools version",version,"or greater has been installed."
+ print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+ """Update our built-in md5 registry"""
+
+ import re
+
+ for name in filenames:
+ base = os.path.basename(name)
+ f = open(name,'rb')
+ md5_data[base] = md5(f.read()).hexdigest()
+ f.close()
+
+ data = [" %r: %r,\n" % it for it in md5_data.items()]
+ data.sort()
+ repl = "".join(data)
+
+ import inspect
+ srcfile = inspect.getsourcefile(sys.modules[__name__])
+ f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+ match = re.search("\nmd5_data = {\n([^}]+)}", src)
+ if not match:
+ print >>sys.stderr, "Internal error!"
+ sys.exit(2)
+
+ src = src[:match.start(1)] + repl + src[match.end(1):]
+ f = open(srcfile,'w')
+ f.write(src)
+ f.close()
+
+
+if __name__=='__main__':
+ if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+ update_md5(sys.argv[2:])
+ else:
+ main(sys.argv[1:])
+
+
+
+
+
+
52 setup.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+
+import glob
+import platform
+import sys
+
+import ez_setup
+ez_setup.use_setuptools()
+
+from setuptools import setup, Extension
+system,node,release,version,machine,processor = platform.uname()
+
+setup(
+ name = 'tempest',
+ version = '0.16',
+ maintainer = 'Russell Power',
+ maintainer_email = 'russell.power@gmail.com',
+ url = 'http://code.google.com/p/py-leveldb/',
+
+ classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Other Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: POSIX',
+ 'Programming Language :: C++',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3.0',
+ 'Programming Language :: Python :: 3.1',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ ],
+
+ description = 'Python bindings for leveldb database library',
+
+ packages = ['tempest'],
+ package_dir = {'tempest': 'src/tempest'},
+
+ ext_modules = [
+ Extension('_tempest',
+ sources = [
+ 'src/C/reval.cc',
+ 'src/C/rcompile.cc',
+ ],
+ libraries = ['stdc++'],
+ )
+ ]
+)
978 src/C/rcompile.cc
@@ -0,0 +1,978 @@
+#include "Python.h"
+
+#include "Python-ast.h"
+#include "node.h"
+#include "pyarena.h"
+#include "ast.h"
+#include "code.h"
+#include "compile.h"
+#include "symtable.h"
+#include "opcode.h"
+#include "marshal.h"
+#include "reval.h"
+
+#include <string.h>
+#include <stdint.h>
+
+#include <vector>
+#include <string>
+
+#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
+#define CODESIZE(op) (HAS_ARG(op) ? 3 : 1)
+
+int is_branch_op(RegisterOp* op) {
+ int opcode = op->code;
+ return (opcode == POP_JUMP_IF_FALSE || opcode == POP_JUMP_IF_TRUE
+ || opcode == JUMP_IF_FALSE_OR_POP || opcode == JUMP_IF_TRUE_OR_POP
+ || opcode == JUMP_ABSOLUTE || opcode == JUMP_FORWARD
+ || opcode == FOR_ITER);
+}
+
+// While compiling, we use an expanded form to represent opcodes. This
+// is translated to a compact instruction stream as the last compilation
+// step.
+typedef struct {
+ int code;
+ int arg;
+
+ // this instruction has been marked dead by an optimization pass,
+ // and should be ignored.
+ int dead;
+
+ JumpLoc branches[2];
+ std::vector<Register> regs;
+} CompilerOp;
+
+static void compilerop_to_regop(CompilerOp* c, RegisterOp* r) {
+ r->code = c->code;
+ r->arg = c->arg;
+ r->branches[0] = c->branches[0];
+ r->branches[1] = c->branches[1];
+ r->num_registers = c->regs.size();
+ for (size_t i = 0; i < c->regs.size(); ++i) {
+ r->regs[i] = c->regs[i];
+ }
+}
+
+struct BasicBlock;
+
+typedef struct BasicBlock {
+ int py_offset;
+ int reg_offset;
+ int idx;
+
+ std::vector<BasicBlock*> exits;
+ std::vector<BasicBlock*> entries;
+ std::vector<CompilerOp*> code;
+
+ // Have we been visited by the current pass already?
+ int visited;
+ int dead;
+} BasicBlock;
+
+static void init_bb(BasicBlock* bb, int offset, int idx) {
+ bb->py_offset = offset;
+ bb->visited = 0;
+ bb->dead = 0;
+ bb->idx = idx;
+}
+
+typedef struct {
+ int target;
+ int stack_pos;
+} RegisterFrame;
+
+typedef struct {
+ int regs[REG_MAX_STACK];
+ int stack_pos;
+
+ RegisterFrame frames[REG_MAX_FRAMES];
+ int num_frames;
+} RegisterStack;
+
+typedef struct {
+ std::vector<BasicBlock*> bbs;
+
+ unsigned char* py_codestr;
+ Py_ssize_t py_codelen;
+
+ int num_reg;
+ int num_consts;
+ int num_locals;
+} CompilerState;
+
+static void init_state(CompilerState* state) {
+}
+
+static BasicBlock* alloc_bb(CompilerState* state) {
+ BasicBlock* bb = new BasicBlock;
+ state->bbs.push_back(bb);
+ return bb;
+}
+
+static void push_frame(RegisterStack* c, int target) {
+ assert(c->num_frames < REG_MAX_FRAMES);
+ RegisterFrame* f = &c->frames[c->num_frames++];
+ f->target = target;
+ f->stack_pos = c->stack_pos;
+}
+
+static RegisterFrame* pop_frame(RegisterStack* c) {
+ assert(c->num_frames > 0);
+ RegisterFrame* f = &c->frames[--c->num_frames];
+ c->stack_pos = f->stack_pos;
+ return f;
+}
+
+static int push_register(RegisterStack* st, int reg) {
+ // fprintf(stderr, "Pushing register %d, pos %d\n", reg, st->stack_pos + 1);
+ assert(st->stack_pos < REG_MAX_STACK);
+ st->regs[++st->stack_pos] = reg;
+ return reg;
+}
+
+static int pop_register(RegisterStack* st) {
+ assert(st->stack_pos >= 0);
+ int reg = st->regs[st->stack_pos--];
+ assert(reg >= -1);
+ // fprintf(stderr, "Popped register %d, pos: %d\n", reg, st->stack_pos + 1);
+ return reg;
+}
+
+static int peek_register(RegisterStack* st, int reg) {
+ return st->regs[st->stack_pos - reg];
+}
+
+void print_stack(RegisterStack* st) {
+ int i;
+ fprintf(stderr, "[");
+ for (i = 0; i <= st->stack_pos; ++i) {
+ fprintf(stderr, "%d, ", st->regs[i]);
+ }
+ fprintf(stderr, "]\n");
+}
+
+static void copy_stack(RegisterStack *from, RegisterStack* to) {
+ memcpy(to->regs, from->regs, sizeof(from->regs));
+ to->stack_pos = from->stack_pos;
+ memcpy(to->frames, from->frames, sizeof(from->frames));
+ to->num_frames = from->num_frames;
+}
+
+static CompilerOp* _add_op(BasicBlock* bb, int opcode, int arg, int num_regs) {
+ CompilerOp* op = new CompilerOp;
+ op->code = opcode;
+ op->regs.resize(num_regs);
+ op->branches[0] = -1;
+ op->branches[1] = -1;
+ op->dead = 0;
+ op->arg = arg;
+ bb->code.push_back(op);
+
+ return op;
+}
+
+static void add_op(BasicBlock* bb, int opcode, int arg, Register reg1,
+ Register reg2, Register reg3, Register reg4) {
+ int num_regs = 0;
+
+ if (reg1 != -1) {
+ num_regs = 1;
+ }
+ if (reg2 != -1) {
+ num_regs = 2;
+ }
+ if (reg3 != -1) {
+ num_regs = 3;
+ }
+ if (reg4 != -1) {
+ num_regs = 4;
+ }
+
+ CompilerOp* op = _add_op(bb, opcode, arg, num_regs);
+
+ switch (num_regs) {
+ case 4:
+ op->regs[3] = reg4;
+ case 3:
+ op->regs[2] = reg3;
+ case 2:
+ op->regs[1] = reg2;
+ case 1:
+ op->regs[0] = reg1;
+ case 0:
+ break;
+ default:
+ assert(0 && "Invalid number of registers for op?");
+ break;
+ }
+}
+
+static CompilerOp* add_varargs_op(BasicBlock* bb, int opcode, int arg,
+ int num_regs) {
+ CompilerOp* op = _add_op(bb, opcode, arg, num_regs);
+ return op;
+}
+
+/*
+ * The main event: convert from a stack machine to an infinite register machine.
+ * We do this using a virtual stack. Instead of opcodes pushing and popping
+ * values from the * stack, we have them push and pop register names. These
+ * register names can then * be used to construct register versions of each
+ * opcode.
+ *
+ * For example, the following operations translate to:
+ *
+ * LOAD_CONST 1
+ * LOAD_CONST 2
+ * ADD
+ *
+ * --->
+ *
+ * r1 = 1 ('push' r1)
+ * r2 = 2 ('push' r2)
+ * r3 = add r1, r2 ('pop' r1, r2)
+ */
+static BasicBlock* registerize(CompilerState* state, RegisterStack *stack,
+ int offset) {
+ Py_ssize_t r;
+ int r1, r2, r3, r4;
+ int oparg = 0;
+ int opcode = 0;
+
+ unsigned char* codestr = state->py_codestr;
+
+ BasicBlock *last = NULL;
+ BasicBlock *entry_point = NULL;
+
+ // If we've already visited this opcode, return the previous block for it.
+ for (size_t i = 0; i < state->bbs.size(); ++i) {
+ BasicBlock *old = state->bbs[i];
+ if (old->py_offset == offset) {
+ return old;
+ }
+ }
+
+ for (; offset < state->py_codelen; offset += CODESIZE(codestr[offset])) {
+ opcode = codestr[offset];
+ oparg = 0;
+ if (HAS_ARG(opcode)) {
+ oparg = GETARG(codestr, offset);
+ }
+
+ /* The following routines only affect the register stack, and their
+ * effect can be captured statically. We therefore do not have to emit
+ * an opcode for them.
+ */
+ switch (opcode) {
+ case NOP:
+ continue;
+ case ROT_TWO:
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ push_register(stack, r1);
+ push_register(stack, r2);
+ continue;
+ case ROT_THREE:
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ r3 = pop_register(stack);
+ push_register(stack, r1);
+ push_register(stack, r3);
+ push_register(stack, r2);
+ continue;
+ default:
+ break;
+ }
+
+ // Check if the opcode we've advanced to has already been generated.
+ // If so, patch ourselves into it and return our entry point.
+ for (size_t i = 0; i < state->bbs.size(); ++i) {
+ BasicBlock *old = state->bbs[i];
+ if (old->py_offset == offset) {
+ assert(entry_point != NULL);
+ assert(last != NULL);
+ last->exits.push_back(old);
+ return entry_point;
+ }
+ }
+
+ BasicBlock *bb = alloc_bb(state);
+ if (!entry_point) {
+ entry_point = bb;
+ }
+
+ if (last) {
+ last->exits.push_back(bb);
+ }
+
+ last = bb;
+ init_bb(bb, offset, state->bbs.size() - 1);
+ switch (opcode) {
+ // Stack pushing/popping
+ case POP_TOP:
+ r1 = pop_register(stack);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ break;
+ case DUP_TOP:
+ r1 = pop_register(stack);
+ push_register(stack, r1);
+ push_register(stack, r1);
+ add_op(bb, INCREF, 0, r1, -1, -1, -1);
+ break;
+ case DUP_TOPX:
+ if (oparg == 2) {
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ add_op(bb, INCREF, 0, r1, -1, -1, -1);
+ add_op(bb, INCREF, 0, r2, -1, -1, -1);
+ push_register(stack, r1);
+ push_register(stack, r2);
+ push_register(stack, r1);
+ push_register(stack, r2);
+ } else {
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ r3 = pop_register(stack);
+ add_op(bb, INCREF, 0, r1, -1, -1, -1);
+ add_op(bb, INCREF, 0, r2, -1, -1, -1);
+ add_op(bb, INCREF, 0, r3, -1, -1, -1);
+ push_register(stack, r3);
+ push_register(stack, r2);
+ push_register(stack, r1);
+ push_register(stack, r3);
+ push_register(stack, r2);
+ push_register(stack, r1);
+ }
+ break;
+ // Load operations: push one register onto the stack.
+ case LOAD_CONST:
+ r1 = push_register(stack, oparg);
+ add_op(bb, INCREF, 0, r1, -1, -1, -1);
+ break;
+ case LOAD_FAST:
+ r1 = push_register(stack, state->num_consts + oparg);
+ add_op(bb, INCREF, 0, r1, -1, -1, -1);
+ break;
+ case LOAD_CLOSURE:
+ case LOAD_DEREF:
+ case LOAD_GLOBAL:
+ case LOAD_LOCALS:
+ case LOAD_NAME:
+ r1 = push_register(stack, state->num_reg++);
+ add_op(bb, opcode, oparg, r1, -1, -1, -1);
+ add_op(bb, INCREF, 0, r1, -1, -1, -1);
+ break;
+ case LOAD_ATTR:
+ r1 = pop_register(stack);
+ r2 = push_register(stack, state->num_reg++);
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ break;
+ case STORE_FAST:
+ r1 = pop_register(stack);
+ // Decrement the old value.
+ add_op(bb, DECREF, 0, state->num_consts + oparg, -1, -1, -1);
+ add_op(bb, opcode, 0, r1, state->num_consts + oparg, -1, -1);
+ break;
+ // Store operations remove one or more registers from the stack.
+ case STORE_DEREF:
+ case STORE_GLOBAL:
+ case STORE_NAME:
+ r1 = pop_register(stack);
+ add_op(bb, opcode, oparg, r1, -1, -1, -1);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ break;
+ case STORE_ATTR:
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ add_op(bb, DECREF, 0, r2, -1, -1, -1);
+ break;
+ case STORE_MAP:
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ r3 = pop_register(stack);
+ add_op(bb, opcode, oparg, r1, r2, r3, -1);
+ push_register(stack, r3);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ add_op(bb, DECREF, 0, r2, -1, -1, -1);
+ break;
+ case STORE_SUBSCR:
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ r3 = pop_register(stack);
+ add_op(bb, opcode, oparg, r1, r2, r3, -1);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ add_op(bb, DECREF, 0, r2, -1, -1, -1);
+ add_op(bb, DECREF, 0, r3, -1, -1, -1);
+ break;
+ case GET_ITER:
+ r1 = pop_register(stack);
+ r2 = push_register(stack, state->num_reg++);
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ add_op(bb, DECREF, oparg, r1, -1, -1, -1);
+ break;
+ case SLICE + 0:
+ case SLICE + 1:
+ case SLICE + 2:
+ case SLICE + 3:
+ r1 = r2 = r3 = r4 = -1;
+ if ((opcode - SLICE) & 2)
+ r3 = pop_register(stack);
+ if ((opcode - SLICE) & 1)
+ r2 = pop_register(stack);
+ r1 = pop_register(stack);
+ r4 = push_register(stack, state->num_reg++);
+
+ if (r2 == -1) {
+ add_op(bb, opcode, oparg, r1, r4, -1, -1);
+ } else {
+ if (r3 == -1) {
+ add_op(bb, opcode, oparg, r1, r2, r4, -1);
+ } else {
+ add_op(bb, opcode, oparg, r1, r2, r3, r4);
+ }
+ }
+ break;
+ case STORE_SLICE + 0:
+ case STORE_SLICE + 1:
+ case STORE_SLICE + 2:
+ case STORE_SLICE + 3:
+ r1 = r2 = r3 = r4 = -1;
+ if ((opcode - STORE_SLICE) & 2)
+ r4 = pop_register(stack);
+ if ((opcode - STORE_SLICE) & 1)
+ r3 = pop_register(stack);
+ r2 = pop_register(stack);
+ r1 = pop_register(stack);
+ if (r3 == -1) {
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ } else {
+ if (r4 == -1) {
+ add_op(bb, opcode, oparg, r1, r2, r3, -1);
+ } else {
+ add_op(bb, opcode, oparg, r1, r2, r3, r4);
+ }
+ }
+ break;
+ case DELETE_SLICE + 0:
+ case DELETE_SLICE + 1:
+ case DELETE_SLICE + 2:
+ case DELETE_SLICE + 3:
+ r1 = r2 = r3 = r4 = -1;
+ if ((opcode - DELETE_SLICE) & 2)
+ r4 = pop_register(stack);
+ if ((opcode - DELETE_SLICE) & 1)
+ r3 = pop_register(stack);
+ r2 = pop_register(stack);
+ r1 = pop_register(stack);
+ if (r3 == -1) {
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ } else {
+ if (r4 == -1) {
+ add_op(bb, opcode, oparg, r1, r2, r3, -1);
+ } else {
+ add_op(bb, opcode, oparg, r1, r2, r3, r4);
+ }
+ }
+ break;
+ case LIST_APPEND:
+ r1 = pop_register(stack);
+ r2 = peek_register(stack, oparg);
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ break;
+ case UNARY_NOT:
+ // Unary operations: pop 1, push 1.
+ r1 = pop_register(stack);
+ r2 = push_register(stack, state->num_reg++);
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ break;
+ case UNARY_POSITIVE:
+ case UNARY_NEGATIVE:
+ case UNARY_CONVERT:
+ case UNARY_INVERT:
+ // Unary operations: pop 1, push 1.
+ r1 = pop_register(stack);
+ r2 = push_register(stack, state->num_reg++);
+ add_op(bb, opcode, oparg, r1, r2, -1, -1);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ break;
+ case BINARY_POWER:
+ case BINARY_MULTIPLY:
+ case BINARY_TRUE_DIVIDE:
+ case BINARY_FLOOR_DIVIDE:
+ case BINARY_MODULO:
+ case BINARY_ADD:
+ case BINARY_SUBTRACT:
+ case BINARY_SUBSCR:
+ case BINARY_LSHIFT:
+ case BINARY_RSHIFT:
+ case BINARY_AND:
+ case BINARY_XOR:
+ case BINARY_OR:
+ case INPLACE_POWER:
+ case INPLACE_MULTIPLY:
+ case INPLACE_DIVIDE:
+ case INPLACE_TRUE_DIVIDE:
+ case INPLACE_FLOOR_DIVIDE:
+ case INPLACE_MODULO:
+ case INPLACE_ADD:
+ case INPLACE_SUBTRACT:
+ case INPLACE_LSHIFT:
+ case INPLACE_RSHIFT:
+ case INPLACE_AND:
+ case INPLACE_XOR:
+ case INPLACE_OR:
+ case COMPARE_OP:
+ // Binary operations: pop 2, push 1.
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ r3 = push_register(stack, state->num_reg++);
+ add_op(bb, opcode, oparg, r1, r2, r3, -1);
+ add_op(bb, DECREF, 0, r1, -1, -1, -1);
+ add_op(bb, DECREF, 0, r2, -1, -1, -1);
+ break;
+ case CALL_FUNCTION:
+ case CALL_FUNCTION_VAR:
+ case CALL_FUNCTION_KW:
+ case CALL_FUNCTION_VAR_KW: {
+ int na = oparg & 0xff;
+ int nk = (oparg >> 8) & 0xff;
+ int n = na + 2 * nk;
+ CompilerOp* f = add_varargs_op(bb, opcode, oparg, n + 2);
+ for (r = n - 1; r >= 0; --r) {
+ f->regs[r] = pop_register(stack);
+ }
+ f->regs[n] = pop_register(stack);
+ f->regs[n + 1] = push_register(stack, state->num_reg++);
+ assert(f->arg == oparg);
+
+// for (r = n; r >= 0; --r) { add_op(bb, DECREF, 0, f->regs[r], -1, -1, -1); }
+ break;
+ }
+ case BUILD_LIST:
+ case BUILD_SET:
+ case BUILD_TUPLE: {
+ CompilerOp* f = add_varargs_op(bb, opcode, oparg, oparg + 1);
+ for (r = 0; r < oparg; ++r) {
+ f->regs[r] = pop_register(stack);
+ }
+ f->regs[oparg] = push_register(stack, state->num_reg++);
+ break;
+ }
+ case UNPACK_SEQUENCE: {
+ CompilerOp* f = add_varargs_op(bb, opcode, oparg, oparg + 1);
+ f->regs[0] = pop_register(stack);
+ for (r = 1; r < oparg + 1; ++r) {
+ f->regs[r] = push_register(stack, state->num_reg++);
+ }
+ break;
+ }
+// case SETUP_EXCEPT:
+// case SETUP_FINALLY:
+ case SETUP_LOOP:
+ push_frame(stack,
+ offset + CODESIZE(state->py_codestr[offset]) + oparg);
+ add_op(bb, opcode, oparg, -1, -1, -1, -1);
+ break;
+ case RAISE_VARARGS:
+ r1 = r2 = r3 = -1;
+ if (oparg == 3) {
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ r3 = pop_register(stack);
+ } else if (oparg == 2) {
+ r1 = pop_register(stack);
+ r2 = pop_register(stack);
+ } else if (oparg == 1) {
+ r1 = pop_register(stack);
+ }
+ add_op(bb, opcode, oparg, r1, r2, r3, -1);
+ break;
+ case POP_BLOCK:
+ pop_frame(stack);
+ add_op(bb, opcode, oparg, -1, -1, -1, -1);
+ break;
+ // Control flow instructions - recurse down each branch with a copy of the current stack.
+ case BREAK_LOOP: {
+ RegisterFrame *f = pop_frame(stack);
+ add_op(bb, opcode, oparg, -1, -1, -1, -1);
+ bb->exits.push_back(registerize(state, stack, f->target));
+ if (bb->exits[0] == NULL) {
+ return NULL;
+ }
+ return entry_point;
+ }
+ case CONTINUE_LOOP: {
+ pop_frame(stack);
+ add_op(bb, opcode, oparg, -1, -1, -1, -1);
+ bb->exits.push_back(registerize(state, stack, oparg));
+ if (bb->exits[0] == NULL) {
+ return NULL;
+ }
+ break;
+ }
+ case FOR_ITER: {
+ RegisterStack a, b;
+ r1 = pop_register(stack);
+ copy_stack(stack, &a);
+ copy_stack(stack, &b);
+ push_register(&a, r1);
+ r2 = push_register(&a, state->num_reg++);
+
+ add_op(bb, opcode, 0, r1, r2, -1, -1);
+
+ // fall-through if iterator had an item, jump forward if iterator is empty.
+ BasicBlock* left = registerize(state, &a,
+ offset + CODESIZE(opcode));
+ BasicBlock* right = registerize(state, &b,
+ offset + CODESIZE(opcode) + oparg);
+ bb->exits.push_back(left);
+ bb->exits.push_back(right);
+ if (left == NULL || right == NULL) {
+ return NULL;
+ }
+ return entry_point;
+ }
+ case JUMP_IF_FALSE_OR_POP:
+ case JUMP_IF_TRUE_OR_POP: {
+ RegisterStack a, b;
+ copy_stack(stack, &a);
+ r1 = pop_register(stack);
+ copy_stack(stack, &b);
+ add_op(bb, opcode, oparg, r1, -1, -1, -1);
+
+ BasicBlock* right = registerize(state, &a, oparg);
+ BasicBlock* left = registerize(state, &b,
+ offset + CODESIZE(opcode));
+ bb->exits.push_back(left);
+ bb->exits.push_back(right);
+ if (left == NULL || right == NULL) {
+ return NULL;
+ }
+ return entry_point;
+ }
+ case POP_JUMP_IF_FALSE:
+ case POP_JUMP_IF_TRUE: {
+ r1 = pop_register(stack);
+ RegisterStack a, b;
+ copy_stack(stack, &a);
+ copy_stack(stack, &b);
+ add_op(bb, opcode, oparg, r1, -1, -1, -1);
+ BasicBlock* left = registerize(state, &a,
+ offset + CODESIZE(opcode));
+ BasicBlock* right = registerize(state, &b, oparg);
+ bb->exits.push_back(left);
+ bb->exits.push_back(right);
+ if (left == NULL || right == NULL) {
+ return NULL;
+ }
+ return entry_point;
+ }
+ case JUMP_FORWARD: {
+ int dst = oparg + offset + CODESIZE(opcode);
+ add_op(bb, JUMP_ABSOLUTE, dst, -1, -1, -1, -1);
+ assert(dst <= state->py_codelen);
+ BasicBlock* exit = registerize(state, stack, dst);
+ bb->exits.push_back(exit);
+ if (exit == NULL) {
+ return NULL;
+ }
+ return entry_point;
+ }
+ case JUMP_ABSOLUTE: {
+ add_op(bb, JUMP_ABSOLUTE, oparg, -1, -1, -1, -1);
+ BasicBlock* exit = registerize(state, stack, oparg);
+ bb->exits.push_back(exit);
+ if (exit == NULL) {
+ return NULL;
+ }
+ return entry_point;
+ }
+ case RETURN_VALUE:
+ r1 = pop_register(stack);
+ add_op(bb, opcode, oparg, r1, -1, -1, -1);
+ return entry_point;
+ case END_FINALLY:
+ case YIELD_VALUE:
+ default:
+// fprintf(stderr, "Unknown opcode %s, arg = %d\n", opcode_to_name(opcode), oparg);
+ return NULL;
+ break;
+ }
+ }
+ return entry_point;
+}
+
+typedef void (*BBPass)(BasicBlock*);
+typedef void (*OpPass)(BasicBlock*, CompilerOp*);
+static void apply_bb_pass(CompilerState* state, BBPass pass) {
+ for (size_t i = 0; i < state->bbs.size(); ++i) {
+ state->bbs[i]->visited = 0;
+ }
+
+ for (size_t i = 0; i < state->bbs.size(); ++i) {
+ if (!state->bbs[i]->visited) {
+ pass(state->bbs[i]);
+ state->bbs[i]->visited = 1;
+ }
+ }
+}
+
+static void apply_op_pass(CompilerState* state, OpPass pass) {
+ size_t i, j;
+ for (i = 0; i < state->bbs.size(); ++i) {
+ BasicBlock* bb = state->bbs[i];
+ if (bb->dead) {
+ continue;
+ }
+ for (j = 0; j < bb->code.size(); ++j) {
+ if (!bb->code[j]->dead) {
+ pass(bb, bb->code[j]);
+ }
+ }
+ }
+
+}
+
+static void bb_nop_pass(BasicBlock* bb) {
+}
+
+static void bb_mark_entries_pass(BasicBlock* bb) {
+ for (size_t i = 0; i < bb->exits.size(); ++i) {
+ BasicBlock* next = bb->exits[i];
+ next->entries.push_back(bb);
+ }
+}
+
+static void remove_dead_ops(BasicBlock* bb) {
+ size_t j = 0;
+ for (size_t i = 0; i < bb->code.size(); ++i) {
+ CompilerOp * op = bb->code[i];
+ if (op->dead) {
+ continue;
+ }
+ bb->code[j++] = bb->code[i];
+ }
+
+ bb->code.resize(j);
+}
+
+static void remove_dead_code(CompilerState* state) {
+ size_t i = 0;
+ size_t pos = 0;
+ for (i = 0; i < state->bbs.size(); ++i) {
+ BasicBlock* bb = state->bbs[i];
+ if (bb->dead) {
+ continue;
+ }
+ remove_dead_ops(bb);
+ state->bbs[pos++] = bb;
+ }
+ state->bbs.resize(pos);
+}
+
+static void bb_fuse_pass(BasicBlock* bb) {
+ if (bb->visited || bb->dead || bb->exits.size() != 1) {
+ fprintf(stderr, "Leaving %d alone.\n", bb->idx);
+ return;
+ }
+
+ BasicBlock* next = bb->exits[0];
+ while (1) {
+ if (next->entries.size() > 1 || next->visited) {
+ break;
+ }
+
+// fprintf(stderr, "Merging %d into %d\n", next->idx, bb->idx);
+ bb->code.insert(bb->code.end(), next->code.begin(), next->code.end());
+
+ next->dead = next->visited = 1;
+ bb->exits = next->exits;
+
+ if (bb->exits.size() != 1) {
+ break;
+ }
+ next = bb->exits[0];
+ }
+}
+
+// For each basic block, find matching increfs and decrefs, and cancel them out.
+static void bb_combine_refs(BasicBlock* bb) {
+ for (size_t i = 0; i < bb->code.size(); ++i) {
+ CompilerOp * decref = bb->code[i];
+ if (decref->dead || decref->code != DECREF) {
+ continue;
+ }
+ for (size_t j = 0; j < i; ++j) {
+ CompilerOp* incref = bb->code[j];
+ if (!incref->dead && incref->code == INCREF && incref->regs[0] == decref->regs[0]) {
+ decref->dead = 1;
+ incref->dead = 1;
+ }
+ }
+ }
+}
+
+static void print_compiler_op(BasicBlock *bb, CompilerOp* op) {
+ fprintf(stderr, "%d :: %s (ARG: %d, ", bb->idx, opcode_to_name(op->code),
+ op->arg);
+ for (size_t i = 0; i < op->regs.size(); ++i) {
+ fprintf(stderr, "%d, ", op->regs[i]);
+ }
+ fprintf(stderr, ")");
+ if (op->dead) {
+ fprintf(stderr, " DEAD ");
+ }
+
+ if (op == bb->code[bb->code.size() - 1]) {
+ fprintf(stderr, "-> [");
+ for (size_t i = 0; i < bb->exits.size(); ++i) {
+ fprintf(stderr, "%d,", bb->exits[i]->idx);
+ }
+ fprintf(stderr, "]");
+ }
+ fprintf(stderr, "\n");
+}
+
+typedef void (*OptPass)(CompilerState*);
+
+static void opt_fuse_bb(CompilerState* state) {
+ apply_bb_pass(state, &bb_mark_entries_pass);
+ apply_bb_pass(state, &bb_fuse_pass);
+}
+
+static void opt_combine_refs(CompilerState* state) {
+ apply_bb_pass(state, &bb_combine_refs);
+}
+
+static void _apply_opt_pass(CompilerState* state, OptPass pass,
+ const char* name) {
+ // fprintf(stderr, "Before %s:\n", name);
+ // apply_op_pass(state, &print_compiler_op);
+
+ pass(state);
+
+ remove_dead_code(state);
+
+// fprintf(stderr, "After %s:\n", name);
+// apply_op_pass(state, &print_compiler_op);
+
+}
+
+#define apply_opt_pass(state, pass) _apply_opt_pass(state, pass, #pass)
+
+static void bb_to_code(CompilerState* state, std::string *out) {
+ RegisterPrelude p;
+ memcpy(&p.magic, REG_MAGIC, 4);
+ p.mapped_registers = 0;
+ p.mapped_labels = 0;
+ p.num_registers = state->num_reg;
+ out->append((char*) &p, sizeof(RegisterPrelude));
+
+// fprintf(stderr, "Converting compiler ops to register ops.\n");
+// apply_op_pass(state, &print_compiler_op);
+
+ // first, dump all of the operations to the output buffer and record
+ // their positions.
+ for (size_t i = 0; i < state->bbs.size(); ++i) {
+ BasicBlock* bb = state->bbs[i];
+ assert(!bb->dead);
+ bb->reg_offset = out->size();
+ for (size_t j = 0; j < bb->code.size(); ++j) {
+ CompilerOp* c = bb->code[j];
+ assert(!c->dead);
+
+ int rop_size = sizeof(RegisterOp)
+ + sizeof(Register) * c->regs.size();
+ size_t offset = out->size();
+ out->resize(out->size() + rop_size);
+ RegisterOp* r = (RegisterOp*) (out->data() + offset);
+ compilerop_to_regop(c, r);
+ }
+ }
+
+ // now patchup the emitted code.
+ Py_ssize_t pos = sizeof(RegisterPrelude);
+ for (size_t i = 0; i < state->bbs.size(); ++i) {
+ BasicBlock* bb = state->bbs[i];
+ RegisterOp *prev = NULL;
+ RegisterOp *op = NULL;
+ for (size_t j = 0; j < bb->code.size(); ++j) {
+ if (prev) {
+ prev->branches[0] = pos;
+ prev->branches[1] = -1;
+ }
+
+ op = (RegisterOp*) (out->data() + pos);
+ assert(op->code <= MAX_CODE);
+
+ // fprintf(stderr, "Reading %d.%d:", i, j);
+ // print_op(op);
+ prev = op;
+ pos += regop_size(op);
+ }
+
+ if (op->code != RETURN_VALUE) {
+ assert(bb->exits[0] != NULL);
+ op->branches[0] = bb->exits[0]->reg_offset;
+ assert(bb->exits[0]->reg_offset > 0);
+ }
+
+ if (bb->exits.size() > 1) {
+ assert(bb->exits.size() == 2);
+ op->branches[1] = bb->exits[1]->reg_offset;
+ assert(bb->exits[1]->reg_offset > 0);
+ } else {
+ op->branches[1] = -1;
+ }
+ }
+}
+
+/*
+ * Transform stack machine bytecode into registerized form.
+ */
+PyObject * PyCode_Registerize(PyCodeObject * code) {
+ if (getenv("PY_NO_REGISTER")) {
+ return NULL;
+ }
+
+ CompilerState *state = new CompilerState;
+ RegisterStack stack;
+
+ int codelen = PyString_GET_SIZE(code->co_code);
+ stack.stack_pos = -1;
+ stack.num_frames = 0;
+
+ init_state(state);
+ state->num_consts = PyTuple_Size(code->co_consts);
+ state->num_locals = code->co_nlocals;
+ // Offset by the number of constants and locals.
+ state->num_reg = state->num_consts + state->num_locals;
+// fprintf(stderr, "Consts: %d, locals: %d, first register: %d\n",
+// state->num_consts, state->num_locals, num_reg);
+
+ state->py_codelen = codelen;
+ state->py_codestr = (unsigned char*) PyString_AsString(code->co_code);
+
+ BasicBlock* entry_point = registerize(state, &stack, 0);
+ if (entry_point == NULL) {
+// fprintf(stderr,
+// "Failed to registerize %s:%d (%s), using stack machine.\n",
+// PyString_AsString(code->co_filename), code->co_firstlineno,
+// PyString_AsString(code->co_name));
+ return NULL;
+ }
+
+ apply_opt_pass(state, &opt_fuse_bb);
+ apply_opt_pass(state, &opt_combine_refs);
+
+ std::string regcode;
+ bb_to_code(state, &regcode);
+ PyObject* regobj = PyString_FromStringAndSize((char*) regcode.data(),
+ regcode.size());
+ delete state;
+ return regobj;
+}
502 src/C/reval.cc
@@ -0,0 +1,502 @@
+#include "Python.h"
+#include "opcode.h"
+#include "reval.h"
+#include "marshal.h"
+
+#include <string.h>
+#include <stdint.h>
+
+#define CODE_FOR_OP(op_ptr) ((const RegisterOp*)op_ptr)->code
+#define LABEL_FOR_OP(op_ptr) labels[CODE_FOR_OP(op_ptr)]
+
+#define PRINT_OP(op) if (debug_print_ops) {print_op(op); }
+
+#define JUMP_TO(op_ptr)\
+ assert(CODE_FOR_OP(op_ptr) <= MAX_CODE);\
+ goto *LABEL_FOR_OP(op_ptr)
+// goto *((RegisterOp*)(op_ptr))->handler
+
+#define START_OP_FIXED(opname, num_registers)\
+ op_##opname: {\
+ const RegisterOp* const op = (RegisterOp*) (code + offset);\
+ PRINT_OP(op)\
+ const int jumpby = (sizeof(RegisterOp) + num_registers * sizeof(Register));\
+ assert(jumpby == regop_size(op));\
+ offset += jumpby;
+
+#define START_OP_BRANCH(opname)\
+ op_##opname: {\
+ const RegisterOp* const op = (RegisterOp*) (code + offset);\
+ PRINT_OP(op)\
+ offset = op->branches[0];
+
+#define END_OP JUMP_TO((code + offset)); }
+
+#define BAD_OP(opname)\
+ op_##opname: { fprintf(stderr, "Not implemented: %s\n", #opname); exit(1); }
+
+#define FALLTHROUGH_OP(opname) op_##opname:
+
+#define BINARY_OP(opname, opfn)\
+ op_##opname: {\
+ RegisterOp* op = (RegisterOp*) (code + offset);\
+ PRINT_OP(op)\
+ offset += sizeof(RegisterOp) + 3 * sizeof(Register);\
+ PyObject *r1 = registers[op->regs[0]];\
+ PyObject *r2 = registers[op->regs[1]];\
+ PyObject *r3 = opfn(r1, r2);\
+ registers[op->regs[2]] = r3;\
+ END_OP
+
+
+PyObject * PyRegEval_EvalFrame(PyFrameObject *f, int throwflag) {
+ const int debug_print_ops = getenv("PY_REG_PRINTOPS") != NULL;
+
+ char* code;
+ Py_ssize_t codelen;
+ PyObject *result = NULL;
+
+ PyString_AsStringAndSize(f->f_code->co_regcode, &code, &codelen);
+
+ RegisterPrelude *prelude = (RegisterPrelude*) code;
+ assert(memcmp(&prelude->magic, REG_MAGIC, 4) == 0);
+
+ register int offset = sizeof(RegisterPrelude);
+
+ // Remap branches to our actual labels.
+// if (!prelude->mapped_labels) {
+// prelude->mapped_labels = 1;
+// for (; offset < codelen; ) {
+// RegisterOp* op = (RegisterOp*)(code + offset);
+// op->handler = LABEL_FOR_OP(op);
+// offset += regop_size(op);
+// }
+// }
+
+ PyObject* registers[prelude->num_registers];
+ PyObject* const consts = f->f_code->co_consts;
+ PyObject* const globals = f->f_globals;
+ PyObject* const names = f->f_code->co_names;
+ PyObject* const locals = f->f_locals;
+ PyObject** fastlocals = f->f_localsplus;
+ const int num_consts = PyTuple_Size(consts);
+ const int num_locals = f->f_code->co_nlocals;
+
+ // setup const and local register aliases.
+ {
+ int i;
+ for (i = 0; i < num_consts; ++i) {
+ registers[i] = PyTuple_GET_ITEM(consts, i);
+ }
+
+ for (i = 0; i < num_locals; ++i) {
+ registers[num_consts + i] = fastlocals[i];
+ }
+ }
+
+
+ fprintf(stderr, "New frame: %s:%d (%d %d %d)\n",
+ PyString_AsString(f->f_code->co_filename), f->f_code->co_firstlineno,
+ num_consts, num_locals, prelude->num_registers);
+
+ static void *labels[] = {
+ &&op_STOP_CODE,
+ &&op_POP_TOP,
+ &&op_ROT_TWO,
+ &&op_ROT_THREE,
+ &&op_DUP_TOP,
+ &&op_ROT_FOUR,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_NOP,
+ &&op_UNARY_POSITIVE,
+ &&op_UNARY_NEGATIVE,
+ &&op_UNARY_NOT,
+ &&op_UNARY_CONVERT,
+ &&op_BAD_OPCODE,
+ &&op_UNARY_INVERT,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BINARY_POWER,
+ &&op_BINARY_MULTIPLY,
+ &&op_BINARY_DIVIDE,
+ &&op_BINARY_MODULO,
+ &&op_BINARY_ADD,
+ &&op_BINARY_SUBTRACT,
+ &&op_BINARY_SUBSCR,
+ &&op_BINARY_FLOOR_DIVIDE,
+ &&op_BINARY_TRUE_DIVIDE,
+ &&op_INPLACE_FLOOR_DIVIDE,
+ &&op_INPLACE_TRUE_DIVIDE,
+ &&op_SLICE,
+ &&op_SLICE,
+ &&op_SLICE,
+ &&op_SLICE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_STORE_SLICE,
+ &&op_STORE_SLICE,
+ &&op_STORE_SLICE,
+ &&op_STORE_SLICE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_DELETE_SLICE,
+ &&op_DELETE_SLICE,
+ &&op_DELETE_SLICE,
+ &&op_DELETE_SLICE,
+ &&op_STORE_MAP,
+ &&op_INPLACE_ADD,
+ &&op_INPLACE_SUBTRACT,
+ &&op_INPLACE_MULTIPLY,
+ &&op_INPLACE_DIVIDE,
+ &&op_INPLACE_MODULO,
+ &&op_STORE_SUBSCR,
+ &&op_DELETE_SUBSCR,
+ &&op_BINARY_LSHIFT,
+ &&op_BINARY_RSHIFT,
+ &&op_BINARY_AND,
+ &&op_BINARY_XOR,
+ &&op_BINARY_OR,
+ &&op_INPLACE_POWER,
+ &&op_GET_ITER,
+ &&op_BAD_OPCODE,
+ &&op_PRINT_EXPR,
+ &&op_PRINT_ITEM,
+ &&op_PRINT_NEWLINE,
+ &&op_PRINT_ITEM_TO,
+ &&op_PRINT_NEWLINE_TO,
+ &&op_INPLACE_LSHIFT,
+ &&op_INPLACE_RSHIFT,
+ &&op_INPLACE_AND,
+ &&op_INPLACE_XOR,
+ &&op_INPLACE_OR,
+ &&op_BREAK_LOOP,
+ &&op_WITH_CLEANUP,
+ &&op_LOAD_LOCALS,
+ &&op_RETURN_VALUE,
+ &&op_IMPORT_STAR,
+ &&op_EXEC_STMT,
+ &&op_YIELD_VALUE,
+ &&op_POP_BLOCK,
+ &&op_END_FINALLY,
+ &&op_BUILD_CLASS,
+ &&op_STORE_NAME,
+ &&op_DELETE_NAME,
+ &&op_UNPACK_SEQUENCE,
+ &&op_FOR_ITER,
+ &&op_LIST_APPEND,
+ &&op_STORE_ATTR,
+ &&op_DELETE_ATTR,
+ &&op_STORE_GLOBAL,
+ &&op_DELETE_GLOBAL,
+ &&op_DUP_TOPX,
+ &&op_LOAD_CONST,
+ &&op_LOAD_NAME,
+ &&op_BUILD_TUPLE,
+ &&op_BUILD_LIST,
+ &&op_BUILD_SET,
+ &&op_BUILD_MAP,
+ &&op_LOAD_ATTR,
+ &&op_COMPARE_OP,
+ &&op_IMPORT_NAME,
+ &&op_IMPORT_FROM,
+ &&op_JUMP_FORWARD,
+ &&op_JUMP_IF_FALSE_OR_POP,
+ &&op_JUMP_IF_TRUE_OR_POP,
+ &&op_JUMP_ABSOLUTE,
+ &&op_POP_JUMP_IF_FALSE,
+ &&op_POP_JUMP_IF_TRUE,
+ &&op_LOAD_GLOBAL,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_CONTINUE_LOOP,
+ &&op_SETUP_LOOP,
+ &&op_SETUP_EXCEPT,
+ &&op_SETUP_FINALLY,
+ &&op_BAD_OPCODE,
+ &&op_LOAD_FAST,
+ &&op_STORE_FAST,
+ &&op_DELETE_FAST,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_RAISE_VARARGS,
+ &&op_CALL_FUNCTION,
+ &&op_MAKE_FUNCTION,
+ &&op_BUILD_SLICE,
+ &&op_MAKE_CLOSURE,
+ &&op_LOAD_CLOSURE,
+ &&op_LOAD_DEREF,
+ &&op_STORE_DEREF,
+ &&op_BAD_OPCODE,
+ &&op_BAD_OPCODE,
+ &&op_CALL_FUNCTION_VAR,
+ &&op_CALL_FUNCTION_KW,
+ &&op_CALL_FUNCTION_VAR_KW,
+ &&op_SETUP_WITH,
+ &&op_BAD_OPCODE,
+ &&op_EXTENDED_ARG,
+ &&op_SET_ADD,
+ &&op_MAP_ADD,
+ &&op_INCREF,
+ &&op_DECREF
+ };
+
+ offset = sizeof(RegisterPrelude);
+ RegisterOp* first_op = (RegisterOp*) (code + offset);
+// print_op(first_op);
+
+ // Let's start going!
+ JUMP_TO(first_op);
+
+ BINARY_OP(BINARY_MULTIPLY, PyNumber_Multiply);
+ BINARY_OP(BINARY_DIVIDE, PyNumber_Divide);
+ BINARY_OP(BINARY_ADD, PyNumber_Add);
+ BINARY_OP(BINARY_SUBTRACT, PyNumber_Subtract);
+ BINARY_OP(BINARY_MODULO, PyNumber_Remainder);
+
+ BINARY_OP(INPLACE_MULTIPLY, PyNumber_InPlaceMultiply);
+ BINARY_OP(INPLACE_DIVIDE, PyNumber_InPlaceDivide);
+ BINARY_OP(INPLACE_ADD, PyNumber_InPlaceAdd);
+ BINARY_OP(INPLACE_SUBTRACT, PyNumber_InPlaceSubtract);
+ BINARY_OP(INPLACE_MODULO, PyNumber_InPlaceRemainder);
+
+
+ BAD_OP(LOAD_FAST)
+ BAD_OP(LOAD_CONST)
+
+ START_OP_FIXED(INCREF, 1)
+ Py_INCREF(registers[op->regs[0]]);
+ END_OP
+ START_OP_FIXED(DECREF, 1)
+ Py_XDECREF(registers[op->regs[0]]);
+ END_OP
+ START_OP_FIXED(LOAD_LOCALS, 1)
+ registers[op->regs[0]] = locals;
+ Py_INCREF(locals);
+ END_OP
+ START_OP_FIXED(LOAD_GLOBAL, 1)
+ PyObject* r1 = PyTuple_GET_ITEM(names, op->arg);
+ PyObject* r2 = PyDict_GetItem(globals, r1);
+ if (r2 == NULL) {
+ r2 = PyDict_GetItem(f->f_builtins, r1);
+ }
+ if (r2 == NULL) {
+ PyErr_SetString(PyExc_NameError, "Global name XXX not defined.");
+ return NULL;
+ }
+ registers[op->regs[0]] = r2;
+ END_OP
+ START_OP_FIXED(LOAD_NAME, 1)
+ PyObject* r1 = PyTuple_GET_ITEM(names, op->arg);
+ PyObject* r2 = PyDict_GetItem(locals, r1);
+ if (r2 == NULL) {
+ r2 = PyDict_GetItem(globals, r1);
+ }
+ if (r2 == NULL) {
+ r2 = PyDict_GetItem(f->f_builtins, r1);
+ }
+ registers[op->regs[0]] = r2;
+ END_OP
+ START_OP_FIXED(STORE_FAST, 2)
+ PyObject* from = registers[op->regs[0]];
+ assert(from != NULL);
+ registers[op->regs[1]] = from;
+ END_OP
+ START_OP_FIXED(STORE_NAME, 1)
+ PyObject* r1 = PyTuple_GET_ITEM(names, op->arg);
+ PyObject* r2 = registers[op->regs[0]];
+ PyObject_SetItem(locals, r1, r2);
+ END_OP
+ START_OP_FIXED(STORE_ATTR, 2)
+ PyObject* t = PyTuple_GET_ITEM(names, op->arg);
+ PyObject* key = registers[op->regs[0]];
+ PyObject* value = registers[op->regs[1]];
+ PyObject_SetAttr(t, key, value);
+ END_OP
+ START_OP_FIXED(STORE_SUBSCR, 3)
+ PyObject* key = registers[op->regs[0]];
+ PyObject* list = registers[op->regs[1]];
+ PyObject* value = registers[op->regs[2]];
+ PyObject_SetItem(list, key, value);
+ END_OP
+ START_OP_FIXED(BINARY_SUBSCR, 3)
+ PyObject* key = registers[op->regs[0]];
+ PyObject* list = registers[op->regs[1]];
+ registers[op->regs[2]] = PyObject_GetItem(list, key);
+ END_OP
+ START_OP_FIXED(LOAD_ATTR, 2)
+ PyObject* obj = registers[op->regs[0]];
+ PyObject* name = PyTuple_GET_ITEM(names, op->arg);
+ registers[op->regs[1]] = PyObject_GetAttr(obj, name);
+ END_OP
+ START_OP_BRANCH(BUILD_TUPLE)
+ int i;
+ PyObject* t = PyTuple_New(op->arg);
+ for (i = 0; i < op->arg; ++i) {
+ PyTuple_SET_ITEM(t, i, registers[op->regs[i]]);
+ }
+ registers[op->regs[op->arg]] = t;
+ END_OP
+ START_OP_BRANCH(BUILD_LIST)
+ int i;
+ PyObject* t = PyList_New(op->arg);
+ for (i = 0; i < op->arg; ++i) {
+ PyList_SET_ITEM(t, i, registers[op->regs[i]]);
+ }
+ registers[op->regs[op->arg]] = t;
+ END_OP
+ FALLTHROUGH_OP(CALL_FUNCTION)
+ FALLTHROUGH_OP(CALL_FUNCTION_VAR)
+ FALLTHROUGH_OP(CALL_FUNCTION_KW)
+ START_OP_BRANCH(CALL_FUNCTION_VAR_KW)
+ int na = op->arg & 0xff;
+ int nk = (op->arg >> 8) & 0xff;
+ int n = nk * 2 + na;
+ int i;
+ PyObject* fn = registers[op->regs[n]];
+
+ assert(n + 2 == op->num_registers);
+
+ PyObject* args = PyTuple_New(na);
+ for (i = 0; i < na; ++i) {
+ PyTuple_SET_ITEM(args, i, registers[op->regs[i]]);
+ }
+
+ PyObject* kwdict = NULL;
+ if (nk > 0) {
+ kwdict = PyDict_New();
+ for (i = na; i < nk * 2; i += 2) {
+ PyDict_SetItem(kwdict, registers[op->regs[i]],
+ registers[op->regs[i + 1]]);
+ }
+ }
+
+ PyObject* res = PyObject_Call(fn, args, kwdict);
+ assert(res != NULL);
+ registers[op->regs[n + 1]] = res;
+ END_OP
+ START_OP_FIXED(GET_ITER, 2)
+ PyObject* res = PyObject_GetIter(registers[op->regs[0]]);
+ registers[op->regs[1]] = res;
+ END_OP
+ START_OP_FIXED(FOR_ITER, 2)
+ PyObject* r1 = PyIter_Next(registers[op->regs[0]]);
+ if (r1) {
+ registers[op->regs[1]] = r1;
+ offset = op->branches[0];
+ } else {
+ offset = op->branches[1];
+ }
+ END_OP
+ FALLTHROUGH_OP(POP_JUMP_IF_FALSE)
+ START_OP_FIXED(JUMP_IF_FALSE_OR_POP, 1)
+ assert(op->branches[0] > 0 && op->branches[1] > 0);
+ offset = !PyObject_IsTrue(registers[op->regs[0]]) == 0 ? op->branches[1] : op->branches[0];
+ END_OP
+ FALLTHROUGH_OP(POP_JUMP_IF_TRUE)
+ START_OP_FIXED(JUMP_IF_TRUE_OR_POP, 1)
+ assert(op->branches[0] > 0 && op->branches[1] > 0);
+ offset = PyObject_IsTrue(registers[op->regs[0]]) > 0 ? op->branches[1] : op->branches[0];
+ END_OP
+ START_OP_FIXED(RETURN_VALUE, 1)
+ result = registers[op->regs[0]];
+ Py_INCREF(result);
+ goto done;
+ END_OP
+ FALLTHROUGH_OP(JUMP_FORWARD)
+ FALLTHROUGH_OP(JUMP_ABSOLUTE)
+ FALLTHROUGH_OP( SETUP_LOOP)
+ START_OP_BRANCH(POP_BLOCK)
+ END_OP
+
+ BAD_OP(BAD_OPCODE);
+ BAD_OP(MAP_ADD);
+ BAD_OP(SET_ADD);
+ BAD_OP(EXTENDED_ARG);
+ BAD_OP(SETUP_WITH);
+ BAD_OP(STORE_DEREF);
+ BAD_OP(LOAD_DEREF);
+ BAD_OP(LOAD_CLOSURE);
+ BAD_OP(MAKE_CLOSURE);
+ BAD_OP(BUILD_SLICE);
+ BAD_OP(MAKE_FUNCTION);
+ BAD_OP(RAISE_VARARGS);
+ BAD_OP(DELETE_FAST);
+ BAD_OP(SETUP_FINALLY);
+ BAD_OP(SETUP_EXCEPT);
+ BAD_OP(CONTINUE_LOOP);
+ BAD_OP(IMPORT_FROM);
+ BAD_OP(IMPORT_NAME);
+ BAD_OP(COMPARE_OP);
+ BAD_OP(BUILD_MAP);
+ BAD_OP(BUILD_SET);
+ BAD_OP(DUP_TOPX);
+ BAD_OP(DELETE_GLOBAL);
+ BAD_OP(STORE_GLOBAL);
+ BAD_OP(DELETE_ATTR);
+ BAD_OP(LIST_APPEND);
+ BAD_OP(UNPACK_SEQUENCE);
+ BAD_OP(DELETE_NAME);
+ BAD_OP(BUILD_CLASS);
+ BAD_OP(END_FINALLY);
+ BAD_OP(YIELD_VALUE);
+ BAD_OP(EXEC_STMT);
+ BAD_OP(IMPORT_STAR);
+ BAD_OP(WITH_CLEANUP);
+ BAD_OP(BREAK_LOOP);
+ BAD_OP(INPLACE_OR);
+ BAD_OP(INPLACE_XOR);
+ BAD_OP(INPLACE_AND);
+ BAD_OP(INPLACE_RSHIFT);
+ BAD_OP(INPLACE_LSHIFT);
+ BAD_OP(PRINT_NEWLINE_TO);
+ BAD_OP(PRINT_ITEM_TO);
+ BAD_OP(PRINT_NEWLINE);
+ BAD_OP(PRINT_ITEM);
+ BAD_OP(PRINT_EXPR);
+ BAD_OP(INPLACE_POWER);
+ BAD_OP(BINARY_OR);
+ BAD_OP(BINARY_XOR);
+ BAD_OP(BINARY_AND);
+ BAD_OP(BINARY_RSHIFT);
+ BAD_OP(BINARY_LSHIFT);
+ BAD_OP(DELETE_SUBSCR);
+ BAD_OP(STORE_MAP);
+ BAD_OP(DELETE_SLICE);
+ BAD_OP(STORE_SLICE);
+ BAD_OP(SLICE);
+ BAD_OP(INPLACE_TRUE_DIVIDE);
+ BAD_OP(INPLACE_FLOOR_DIVIDE);
+ BAD_OP(BINARY_TRUE_DIVIDE);
+ BAD_OP(BINARY_FLOOR_DIVIDE);
+ BAD_OP(BINARY_POWER);
+ BAD_OP(UNARY_INVERT);
+ BAD_OP(UNARY_CONVERT);
+ BAD_OP(UNARY_NOT);
+ BAD_OP(UNARY_NEGATIVE);
+ BAD_OP(UNARY_POSITIVE);
+ BAD_OP(NOP);
+ BAD_OP(ROT_FOUR);
+ BAD_OP(DUP_TOP);
+ BAD_OP(ROT_THREE);
+ BAD_OP(ROT_TWO);
+ BAD_OP(POP_TOP);
+ BAD_OP(STOP_CODE);
+
+
+done:
+Py_INCREF(result);
+fprintf(stderr, "Leaving reval frame... %p\n", result);
+return result;
+}
59 src/C/reval.h
@@ -0,0 +1,59 @@
+#ifndef REVAL_H_
+#define REVAL_H_
+
+// Definitions for the register compiler/evaluator.
+
+#include "frameobject.h"
+
+#define REG_MAX_STACK 256
+#define REG_MAX_FRAMES 32
+#define REG_MAX_BBS 1024
+
+#define REG_MAGIC "REG1"
+
+// Register layout --
+//
+// Each function call pushes a new set of registers for evaluation.
+//
+// The first portion of the register file is aliased to the function
+// locals and consts. This is followed by general registers.
+// [0..#consts][0..#locals][general registers]
+typedef int16_t Register;
+typedef int16_t JumpLoc;
+typedef void* JumpAddr;
+
+typedef struct {
+ int32_t magic;
+ int16_t num_registers;
+ int16_t mapped_labels :1;
+ int16_t mapped_registers :1;
+ int16_t reserved :14;
+} RegisterPrelude;
+
+typedef struct {
+ uint64_t code :8;
+ uint64_t arg :16;
+ uint64_t reg1 :16;
+ uint64_t reg2 :16;
+ uint64_t jump :16;
+} FixedRegOp;
+
+typedef struct {
+ uint8_t code;
+ uint16_t arg;
+ uint8_t num_registers;
+ JumpLoc branches[2];
+ Register regs[0];
+} VarRegOp;
+
+static inline Py_ssize_t regop_size(const VarRegOp* op) {
+ return sizeof(VarRegOp) + sizeof(Register) * op->num_registers;
+}
+
+static inline Py_ssize_t regop_size(const FixedRegOp* op) {
+ return sizeof(FixedRegOp);
+}
+
+PyAPI_FUNC(PyObject*) PyRegEval_EvalFrame(PyFrameObject *f, int throwflag);
+
+#endif /* REVAL_H_ */
0  src/tempest/__init__.py
No changes.
111 src/tempest/gen_eval.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# encoding: utf-8
+'''
+Generates C++ code for executing registerized bytecode.
+@copyright: 2013 Russell Power. All rights reserved.
+@license: Apache License 2.0
+'''
+
+
+import logging
+import sys
+import os
+from opcode import opmap, opname
+
+from optparse import OptionParser
+
+class Ops:
+ pass
+
+for name, op in opmap.items():
+ setattr(Ops, name, op)
+
+def fmt(s):
+ f = sys._getframe()
+ instance_vars = [(k, getattr(k)) for k in dir(f.f_back.f_locals['self'])]
+ local_vars = f.f_back.f_locals
+ all_vars = dict(local_vars)
+ for k, v in instance_vars:
+ if not k in all_vars:
+ all_vars[k] = v
+
+ return s % all_vars
+
+def generator_to_string(g):
+ if isinstance(g, str): return g
+ return '\n'.join(g)
+
+class OpcodeGenerator(object):
+ def __init__(self, opcode, num_src_reg, num_dst_reg):
+ self.opcode = opcode
+ self.num_src_reg = num_src_reg
+ self.num_dst_reg = num_dst_reg
+ self.num_reg = num_dst_reg + num_src_reg
+
+ def src(self, idx): return 'src_%d' % idx
+ def dst(self, idx): return 'dst_%d' % idx
+
+ def _load_register(self, idx, dst):
+ return '%s = registers[op->reg_%d];' % (dst, idx)
+
+ def _store_register(self, idx, value):
+ return 'registers[op->reg_%d] = %s;' % (idx + self.num_src_reg, value)
+
+ def generate(self):
+ yield 'op_%s:' % opname[self.opcode]
+ yield '{'
+ yield 'RegisterOp%d op = *((RegisterOp%d*)(code + offset));' % (self.num_reg, self.num_reg)
+ for r in range(self.num_src_reg): yield self._load_register(r, 'PyObject* %s' % self.src(r))
+ yield generator_to_string(self._generate())
+ for r in range(self.num_dst_reg): yield self._store_register(r, self.dst(r))
+ yield '}'
+
+
+class BinOpGenerator(OpcodeGenerator):
+ def __init__(self, opcode, cfunc):
+ OpcodeGenerator.__init__(self, opcode, num_src_reg=2, num_dst_reg=1)
+ self.cfunc = cfunc
+
+ def _generate(self):
+ return '%s = %s(%s, %s);' % (self.dst(0), self.cfunc, self.src(0), self.src(1))
+
+opcode_to_gen = {}
+opcode_to_gen[Ops.BINARY_POWER] = BinOpGenerator(Ops.BINARY_POWER, 'PyNumber_Power')
+opcode_to_gen[Ops.BINARY_MULTIPLY] = BinOpGenerator(Ops.BINARY_MULTIPLY, 'PyNumber_Multiply')
+opcode_to_gen[Ops.BINARY_DIVIDE] = BinOpGenerator(Ops.BINARY_DIVIDE, 'PyNumber_Divide')
+opcode_to_gen[Ops.BINARY_MODULO] = BinOpGenerator(Ops.BINARY_MODULO, 'PyNumber_Modulo')
+opcode_to_gen[Ops.BINARY_ADD] = BinOpGenerator(Ops.BINARY_ADD, 'PyNumber_Add')
+opcode_to_gen[Ops.BINARY_SUBTRACT] = BinOpGenerator(Ops.BINARY_SUBTRACT, 'PyNumber_Subtract')
+opcode_to_gen[Ops.BINARY_SUBSCR] = BinOpGenerator(Ops.BINARY_SUBSCR, 'PyNumber_Subscr')
+opcode_to_gen[Ops.BINARY_FLOOR_DIVIDE] = BinOpGenerator(Ops.BINARY_FLOOR_DIVIDE, 'PyNumber_FloorDivide')
+opcode_to_gen[Ops.BINARY_TRUE_DIVIDE] = BinOpGenerator(Ops.BINARY_TRUE_DIVIDE, 'PyNumber_TrueDivide')
+
+def main(argv=None):
+ program_name = os.path.basename(sys.argv[0])
+
+ if argv is None:
+ argv = sys.argv[1:]
+
+ parser = OptionParser()
+ parser.add_option("-o", "--out", dest="outfile", help="set output path [default: %default]", metavar="FILE")
+ parser.add_option("-v", "--verbose", dest="verbose", action="count", help="set verbosity level [default: %default]")
+ parser.set_defaults(outfile="./out.txt", infile="./in.txt")
+ (opts, args) = parser.parse_args(argv)
+
+ logging.basicConfig(format='%(asctime)s %(filename)s:%(funcName)s %(message)s',
+ level=logging.DEBUG if opts.verbose else logging.INFO)
+
+ print 'void PyRegEval_EvalFrame(PyFrameObject* f) {'
+ print 'static void* labels[] = {'
+ for idx in range(len(opname)):
+ if idx in opcode_to_gen:
+ print '&&op_%s,' % opname[idx]
+ else:
+ print '&&op_BAD,'
+ print '};'
+ for opcode, generator in opcode_to_gen.items():
+ print generator_to_string(generator.generate())
+ print '}'
+
+if __name__ == "__main__":
+ sys.exit(main())

0 comments on commit 012fcd6

Please sign in to comment.
Something went wrong with that request. Please try again.