Commits

ebo committed 760ad68

Updated JIT to allow trace trees

  • Participants
  • Parent commits 4b7e47b

Comments (0)

Files changed (1)

 # HG changeset patch
-# Parent a1ffb6c6871186e9992bb9a567d395443a17748b
+# Parent 2d146914d446edd1f9c66921c1d11d67d47e66be
 
 diff --git a/.hgignore b/.hgignore
 --- a/.hgignore
 +++ b/.hgignore
-@@ -87,3 +87,4 @@
+@@ -48,6 +48,8 @@
+ *.pyd
+ *.cover
+ *~
++*orig
++*rej
+ Lib/lib2to3/*.pickle
+ Lib/test/data/*
+ Misc/*.wpu
+@@ -88,3 +90,4 @@
  .coverage
  coverage/
  htmlcov/
  } PyCodeObject;
  
  /* Masks for co_flags above */
+diff --git a/Include/frameobject.h b/Include/frameobject.h
+--- a/Include/frameobject.h
++++ b/Include/frameobject.h
+@@ -46,6 +46,8 @@
+        bytecode index. */
+     int f_lineno;               /* Current line number */
+     int f_iblock;               /* index in f_blockstack */
++    int f_bail_blockid;
++    int f_bail_opcodeid;
+     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
+     PyObject *f_localsplus[1];  /* locals+stack, dynamically sized */
+ } PyFrameObject;
 diff --git a/Include/opcode.h b/Include/opcode.h
 --- a/Include/opcode.h
 +++ b/Include/opcode.h
-@@ -146,7 +146,9 @@
+@@ -146,7 +146,10 @@
     as we want it to be available to both frameobject.c and ceval.c, while
     remaining private.*/
  #define EXCEPT_HANDLER 257
 +#define JIT_CALL 258
 +#define JIT_ENTER_FUNC 259
 +#define JIT_EXIT_FUNC 260
++#define JIT_BAIL 261
  
  enum cmp_op {PyCmp_LT=Py_LT, PyCmp_LE=Py_LE, PyCmp_EQ=Py_EQ, PyCmp_NE=Py_NE, PyCmp_GT=Py_GT, PyCmp_GE=Py_GE,
               PyCmp_IN, PyCmp_NOT_IN, PyCmp_IS, PyCmp_IS_NOT, PyCmp_EXC_MATCH, PyCmp_BAD};
 new file mode 100644
 --- /dev/null
 +++ b/JIT/PyTypeBuilder.h
-@@ -0,0 +1,290 @@
+@@ -0,0 +1,292 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_PYTYPEBUILDER_H_
 +#define PYTHON_PYTYPEBUILDER_H_
 +    DEFINE_FIELD(PyFrameObject, f_lasti)
 +    DEFINE_FIELD(PyFrameObject, f_lineno)
 +    DEFINE_FIELD(PyFrameObject, f_iblock)
++    DEFINE_FIELD(PyFrameObject, f_bail_blockid)
++    DEFINE_FIELD(PyFrameObject, f_bail_opcodeid)
 +    DEFINE_FIELD(PyFrameObject, f_blockstack)
 +    DEFINE_FIELD(PyFrameObject, f_localsplus)
 +  };
 new file mode 100644
 --- /dev/null
 +++ b/JIT/global_jit_data.cc
-@@ -0,0 +1,192 @@
+@@ -0,0 +1,194 @@
 +#include "Python.h"
 +
 +#include "osdefs.h"
 +#include "global_jit_data.h"
 +#include "JIT/PyTypeBuilder.h"
 +#include "JIT/SingleFunctionInliner.h"
++#include "JIT/jit_tracer.h"
 +
 +#include "llvm/ADT/OwningPtr.h"
 +#include "llvm/ADT/StringRef.h"
 +
 +  for (size_t i = 0; i < obj->funcs.size(); ++i) {
 +    obj->funcs[i].func->eraseFromParent();
++    delete obj->funcs[i].root;
 +  }
 +
 +  delete obj;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/global_jit_data.h
-@@ -0,0 +1,224 @@
+@@ -0,0 +1,235 @@
 +// -*- C++ -*-
 +//
 +
 +class ExecutionEngine;
 +}
 +
++namespace jit {
++  const char *
++  opcode2name(int opcode);
++  class JITTraceRoot;
++}
++
 +struct PyGlobalJITData {
 +public:
 +  static PyGlobalJITData *Get();
 +
 +inline std::ostream& operator<<(std::ostream& stream, const TraceEntry &e)
 +{
++  const char *name = jit::opcode2name(e.opcode);
 +  stream << "<TE: " << e.code
-+         << " " << e.pc
-+         << " " << e.opcode
-+         << " " << e.oparg
++         << " " << e.pc;
++  if (name)
++    stream << " " << name;
++  else
++    stream << " " << e.opcode;
++  stream << " " << e.oparg
 +         << " " << e.flag
 +         << ">";
 +  return stream;
 +private:
 +  // This is called when a merge point is encountered and compiles the trace
 +  void do_trace(PyCodeObject *code, size_t start);
++  void do_trace_on_bail(PyCodeObject *code, std::vector<TraceEntry>& cut_trace);
 +
 +private:
 +  bool active_;
 +  int opcode;
 +  llvm::Function *func;
 +  pyfunc_t trace;
-+  std::vector<TraceEntry> entries;
++  jit::JITTraceRoot *root;
 +};
 +
 +struct _JITCode {
 +#endif
 +
 +#endif
+diff --git a/JIT/jit_analyse.cc b/JIT/jit_analyse.cc
+new file mode 100644
+--- /dev/null
++++ b/JIT/jit_analyse.cc
+@@ -0,0 +1,380 @@
++#include "Python.h"
++#include "Include/opcode.h"
++
++#include "JIT/global_jit_data_fwd.h"
++#include "JIT/global_jit_data.h"
++#include "JIT/jit_fbuilder.h"
++#include "JIT/jit_tracer.h"
++
++#include <iostream>
++
++
++namespace jit {
++
++  static int analyse_split(int opid,
++                           std::vector<TraceEntry>::iterator &iter,
++                           std::vector<JITTraceContainer *> &next,
++                           JITOpBuilder &opb,
++                           JITStack &stack,
++                           JITLocals &locals,
++                           std::vector<JITBasicBlock *> &next_blocks);
++
++  static int analyse_trace(int opid,
++                           std::vector<TraceEntry>::iterator &iter,
++                           std::vector<TraceEntry>::iterator &end,
++                           JITOpBuilder &opb,
++                           JITStack &stack,
++                           JITLocals &locals);
++
++  void static
++  createBinaryOp(JITOpBuilder &opb,
++                 JITStack &stack, JITLocals &locals,
++                 TraceEntry &entry,
++                 bool inplace);
++
++  JITBasicFunction *
++  JITTraceRoot::analyse()
++  {
++    JITBasicFunction *bfunc = new JITBasicFunction();
++    JITStack stack(bfunc);
++    JITLocals locals(bfunc);
++    JITOpBuilder opb(bfunc);
++
++    assert(parts.size() > 0);
++    JITTraceContainer *start = parts.front();
++    assert(start->entries.size() > 0);
++
++    int result = start->analyse(bfunc, opb, stack, locals);
++    if (result != 0) {
++      delete bfunc;
++      return NULL;
++    }
++
++    return bfunc;
++  }
++
++
++  int
++  JITTraceContainer::analyse(JITBasicFunction *bfunc,
++                             JITOpBuilder &opb,
++                             JITStack &stack, JITLocals &locals)
++  {
++    assert(this->entries.size() > 0);
++
++    typedef std::vector<TraceEntry>::iterator iter_t;
++    opb.createBlockInfo(this->id);
++    iter_t begin = this->entries.begin();
++    iter_t end = this->entries.end();
++    if (this->next.size() > 0) {
++      --end;
++    }
++
++    for(iter_t iter = begin; iter != end; ++iter) {
++      int opid = iter - begin;
++      int res = analyse_trace(opid, iter, end, opb, stack, locals);
++      assert(res == 0);
++    }
++
++    if (this->next.size() > 0) {
++      std::vector<JITBasicBlock *> next_blocks;
++      int opid = end - begin;
++      int res = analyse_split(opid, end, this->next, opb, stack, locals, next_blocks);
++      assert(res == 0);
++      assert(next_blocks.size() == this->next.size());
++
++      for(size_t i = 0; i < this->next.size(); ++i) {
++        JITStack next_stack(stack);
++        JITLocals next_locals(locals);
++        JITOpBuilder next_opb(next_blocks[i]);
++
++        bfunc->push_back(next_blocks[i]);
++        res = this->next[i]->analyse(bfunc, next_opb, next_stack, next_locals);
++        assert(res == 0);
++      }
++    }
++    else {
++      opb.createTraceEnd(stack, locals);
++    }
++    return 0;
++  }
++
++  static int analyse_split(int opid,
++                           std::vector<TraceEntry>::iterator &iter,
++                           std::vector<JITTraceContainer *> &next,
++                           JITOpBuilder &opb,
++                           JITStack &stack,
++                           JITLocals &locals,
++                           std::vector<JITBasicBlock *> &next_blocks)
++  {
++    int pc = iter->pc;
++    int opcode = iter->opcode;
++    int oparg = iter->oparg;
++    int flag = iter->flag;
++
++    // std::cout << "PC " << pc << " " << stack.stack.size() << "\n";
++    opb.createOpcodeInfo(pc, opid, stack, locals);
++
++    JITValue *v = NULL;
++
++    switch (opcode) {
++
++    case POP_JUMP_IF_FALSE:
++      assert(next.size() == 2);
++      v = stack.Pop();
++      next_blocks.push_back(new JITBasicBlock());
++      next_blocks.push_back(new JITBasicBlock());
++
++      // Set guard to split control flow
++      opb.createGuardTrueSplit(v, next_blocks, pc, stack, locals);
++      if (flag != TR_STANDARD) {
++        // GuardTrueSplit is symmetric. When the jump is taken, the blocks are
++        // switched
++        std::swap(next_blocks[0], next_blocks[1]);
++      }
++      break;
++
++    default:
++      std::cout << "Unkown Split Opcode " << opcode << "\n";
++      assert(false);
++      break;
++    }
++
++    // std::cout << "PC " << pc << " " << stack.stack.size() << "\n";
++    return 0;
++  }
++
++  static int analyse_trace(int opid,
++                           std::vector<TraceEntry>::iterator &iter,
++                           std::vector<TraceEntry>::iterator &end,
++                           JITOpBuilder &opb,
++                           JITStack &stack,
++                           JITLocals &locals)
++  {
++    int pc = iter->pc;
++    int opcode = iter->opcode;
++    int oparg = iter->oparg;
++    int flag = iter->flag;
++    PyTypeObject* arg0 = iter->arg0;
++    PyTypeObject* arg1 = iter->arg1;
++
++    JITValue *w = NULL;
++    JITValue *v = NULL;
++    JITValue *u = NULL;
++    JITValue *x = NULL;
++
++    // std::cout << "PC " << pc << " " << stack.stack.size() << "\n";
++    opb.createOpcodeInfo(pc, opid, stack, locals);
++
++    switch (opcode) {
++    case FOR_ITER:
++      v = stack.Top();
++      x = opb.createForIter(v);
++      opb.createGuardNull(x, BH_FOR_ITER_EXC, pc, stack, locals);
++      stack.Push(x);
++      break;
++
++    case STORE_FAST:
++      w = locals.Load(oparg);
++      opb.createXDecRef(w);
++
++      v = stack.Pop();
++      if (arg0 != NULL)
++        v->registerStaticType(arg0);
++      locals.Store(oparg, v);
++      break;
++
++      case LOAD_FAST:
++        v = locals.Load(oparg);
++        if (!hasNullGuard(v)) {
++          opb.createGuardNull(v, BH_LOAD_FAST_FAIL, pc, stack, locals);
++        }
++        opb.createIncRef(v);
++        stack.Push(v);
++        break;
++
++      case LOAD_CONST:
++        v = opb.createLoadConst(oparg);
++        opb.createIncRef(v);
++        stack.Push(v);
++        break;
++
++      case LOAD_GLOBAL:
++        v = opb.createLoadGlobal(oparg);
++        if (!hasNullGuard(v)) {
++          opb.createGuardNull(v, BH_EXC_RAISED, pc, stack, locals);
++        }
++        opb.createIncRef(v);
++        stack.Push(v);
++        break;
++
++      case LOAD_ATTR:
++        v = stack.Pop();
++        x = opb.createLoadAttr(v, oparg);
++        opb.createDecRef(v);
++        if (!hasNullGuard(x)) {
++          opb.createGuardNull(x, BH_EXC_RAISED, pc, stack, locals);
++        }
++        stack.Push(x);
++        break;
++
++      case STORE_ATTR:
++        v = stack.Pop();
++        u = stack.Pop();
++        opb.createStoreAttr(v, u, oparg, stack, locals);
++        opb.createDecRef(v);
++        opb.createDecRef(u);
++        break;
++
++      case COMPARE_OP:
++        w = stack.Pop();
++        v = stack.Pop();
++        if (arg0 != NULL)
++          v->registerStaticType(arg0);
++        if (arg1 != NULL)
++          w->registerStaticType(arg1);
++        x = opb.createCompareOp(v, w, oparg);
++        if (!hasNullGuard(x)) {
++          opb.createGuardNull(x, BH_BINARY_OP_FAIL, pc, stack, locals);
++        }
++        stack.Push(x);
++        break;
++
++      case POP_JUMP_IF_FALSE:
++        v = stack.Pop();
++        if (flag == TR_STANDARD) {
++          opb.createGuardTrue(v, BH_JUMP_ARG, pc, stack, locals);
++        }
++        else {
++          opb.createGuardFalse(v, BH_NEXT_OPCODE, pc, stack, locals);
++        }
++        break;
++
++      case INPLACE_ADD:
++      case INPLACE_SUBTRACT:
++      case INPLACE_MULTIPLY:
++      case INPLACE_FLOOR_DIVIDE:
++      case INPLACE_TRUE_DIVIDE:
++        createBinaryOp(opb, stack, locals, *iter, true);
++        break;
++
++      case BINARY_ADD:
++      case BINARY_SUBTRACT:
++      case BINARY_MULTIPLY:
++      case BINARY_FLOOR_DIVIDE:
++      case BINARY_TRUE_DIVIDE:
++      case BINARY_SUBSCR:
++        createBinaryOp(opb, stack, locals, *iter, false);
++        break;
++
++      case JUMP_ABSOLUTE:
++        break;
++
++      case JUMP_FORWARD:
++        break;
++
++      case POP_TOP:
++        v = stack.Pop();
++        opb.createDecRef(v);
++        break;
++
++      case ROT_TWO:
++        v = stack.Pop();
++        w = stack.Pop();
++        stack.Push(v);
++        stack.Push(w);
++        break;
++
++      case ROT_THREE:
++        v = stack.Pop();
++        w = stack.Pop();
++        x = stack.Pop();
++        stack.Push(v);
++        stack.Push(x);
++        stack.Push(w);
++        break;
++
++      case DUP_TOP:
++        v = stack.Top();
++        opb.createIncRef(v);
++        stack.Push(v);
++        break;
++
++      case DUP_TOP_TWO:
++        x = stack.Pop();
++        opb.createIncRef(x);
++        w = stack.Pop();
++        opb.createIncRef(w);
++        stack.Push(w);
++        stack.Push(x);
++        stack.Push(w);
++        stack.Push(x);
++        break;
++
++      case STORE_SUBSCR:
++        w = stack.Pop();
++        v = stack.Pop();
++        u = stack.Pop();
++        opb.createStoreSubscr(v, w, u, stack, locals);
++        opb.createDecRef(u);
++        opb.createDecRef(v);
++        opb.createDecRef(w);
++        break;
++
++    default:
++      std::cout << "Unkown Opcode " << opcode << "\n";
++      assert(false);
++      break;
++    }
++
++    // std::cout << "PC " << pc << " " << stack.stack.size() << "\n";
++    return 0;
++  }
++
++
++  void static
++  createBinaryOp(JITOpBuilder &opb,
++                 JITStack &stack, JITLocals &locals,
++                 TraceEntry &entry,
++                 bool inplace)
++  {
++    int opcode = entry.opcode;
++    JITValue *w = stack.Top();
++    JITValue *v = stack.Second();
++    if (entry.arg0 != NULL)
++      v->registerStaticType(entry.arg0);
++    if (entry.arg1 != NULL)
++      w->registerStaticType(entry.arg1);
++
++    BinaryOpImpl *impl = BinaryOpImpl::create(opcode,
++                                              entry.arg0, entry.arg1,
++                                              stack, locals);
++    assert(impl != NULL);
++
++
++    if (impl->inlined()) {
++      if (!hasTypeGuard(v)) {
++        opb.createGuardType(v, entry.arg0, BH_NO_BLACKHOLE, entry.pc,
++                              stack, locals);
++      }
++
++      if (!hasTypeGuard(w)) {
++        opb.createGuardType(w, entry.arg1, BH_NO_BLACKHOLE, entry.pc,
++                              stack, locals);
++      }
++      v = opb.createExtractValue(v);
++      w = opb.createExtractValue(w);
++    }
++
++    stack.Pop();
++    stack.Pop();
++
++    JITValue *x = opb.createGenericBinOp(impl, inplace, v, w);
++
++    assert(x != NULL);
++    if (!hasNullGuard(x)) {
++      opb.createGuardNull(x, BH_BINARY_OP_FAIL, entry.pc, stack, locals);
++    }
++    stack.Push(x);
++  }
++
++}
 diff --git a/JIT/jit_binop.cc b/JIT/jit_binop.cc
 new file mode 100644
 --- /dev/null
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_binop.h
-@@ -0,0 +1,47 @@
+@@ -0,0 +1,50 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_BINOP_H_
 +#define PYTHON_JIT_BINOP_H_
 +
 +  class BinaryOpImpl {
 +  public:
++    BinaryOpImpl() {}
++    virtual ~BinaryOpImpl() {}
++
 +    static BinaryOpImpl *create(int opcode, PyTypeObject *arg0, PyTypeObject *arg1,
 +                                JITStack &stack, JITLocals &locals);
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_blackhole.cc
-@@ -0,0 +1,136 @@
+@@ -0,0 +1,142 @@
 +#include "Python.h"
 +#include "frameobject.h"
 +#include "opcode.h"
 +    PyCodeObject *co = frame->f_code;
 +    unsigned char* first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code);
 +    unsigned char* next_instr = first_instr + frame->f_lasti;
++    PyJITTracer *trace = PyJITTracer_GET();
++
++    trace->trace(co, frame->f_lasti, JIT_BAIL, reason);
++    trace->setType(0, reinterpret_cast<PyTypeObject*>(frame->f_bail_blockid));
++    trace->setType(1, reinterpret_cast<PyTypeObject*>(frame->f_bail_opcodeid));
 +
 +    bh_tracker->blackhole(reason);
 +
-+    // std::cout << "-->BAIL\n" << "BAIL On: " << co << " " << frame->f_lasti
++    // std::cout << "-->BAIL\n"
++    //           << "BAIL On: " << co << " " << frame->f_lasti
 +    //           << " " << reason << "\n";
 +    // if (PyObject *obj = PyErr_Occurred()) {
 +    //   PyObject_Print(obj, stdout, 0);
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_env.cc
-@@ -0,0 +1,75 @@
+@@ -0,0 +1,104 @@
 +#include "Python.h"
 +
 +#include "global_jit_data_fwd.h"
 +    if (stack.size() > 0) {
 +      JITValue *v = stack.back();
 +      stack.pop_back();
++      if (stack.size() == 0) {
++        std::cout << "*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*\n";
++      }
 +      return v;
 +    }
 +
++    auto &loaded = frame_->stack();
++
++    // Pull value from shared loaded_stack
++    if (static_cast<int>(loaded.size()) > stack_counter_) {
++      return loaded[stack_counter_++];
++    }
++
 +    JITStackValue *v = new JITStackValue;
-+    this->loaded_stack.push_back(v);
++    loaded.push_back(v);
++    ++stack_counter_;
 +    return v;
 +  }
 +
 +    return v;
 +  }
 +
++  JITLocals::JITLocals(JITBasicFrame *frame, int num)
++      : locals(num, NULL), frame_(frame), no_load_(false) {}
++
++  JITLocals::JITLocals(const JITLocals &other)
++      : locals(other.locals), frame_(other.frame_), no_load_(other.no_load_) {}
++
 +  JITValue *
 +  JITLocals::Load(size_t num)
 +  {
 +    }
 +    if (locals[num] == NULL) {
 +      if (!no_load_) {
-+        JITLocalValue *v = new JITLocalValue(num);
++        JITLocalValue *v = nullptr;
++
++        for (auto val : frame_->locals()) {
++          if (val->number() == static_cast<int>(num)) {
++            v = val;
++            break;
++          }
++        }
++
++        if (v == nullptr) {
++          v = new JITLocalValue(num);
++          frame_->locals().push_back(v);
++        }
 +        locals[num] = v;
-+        loaded_locals.push_back(v);
 +      }
 +      else {
 +        assert(false);
 +      }
 +    }
++
 +    return locals[num];
 +  }
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_env.h
-@@ -0,0 +1,55 @@
+@@ -0,0 +1,59 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_ENV_H_
 +#define PYTHON_JIT_ENV_H_
 +  class JITValue;
 +  class JITStackValue;
 +  class JITLocalValue;
++  class JITBasicFrame;
 +
 +  class JITStack {
 +  public:
-+    JITStack()
++    JITStack(JITBasicFrame *frame) : frame_(frame), stack_counter_(0)
 +    {}
-+    ~JITStack()
-+    {}
++    JITStack(const JITStack &other)
++        : stack(other.stack), frame_(other.frame_),
++          stack_counter_(other.stack_counter_) {}
++    ~JITStack() {}
 +
 +    void Push(JITValue *value);
 +    JITValue *Pop();
 +    JITValue *Second();
 +
 +    std::vector<JITValue *> stack;
-+    std::vector<JITStackValue *> loaded_stack;
-+    int stack_counter;
++  private:
++    JITBasicFrame *frame_;
++    // How many values were already loaded from the frame
++    int stack_counter_;
 +  };
 +
 +  class JITLocals {
 +  public:
-+    JITLocals(int num = 0)
-+      : locals(num, NULL), no_load_(false)
-+    {}
++    JITLocals(JITBasicFrame *frame, int num = 0);
++    JITLocals(const JITLocals &other);
 +
 +    void setNoLoad(bool no_load) {
 +      no_load_ = no_load;
 +    void Store(size_t, JITValue *);
 +
 +    std::vector<JITValue *> locals;
-+    std::vector<JITLocalValue *> loaded_locals;
 +  private:
++    JITBasicFrame *frame_;
 +    bool no_load_;
 +  };
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_fbuilder.cc
-@@ -0,0 +1,381 @@
+@@ -0,0 +1,428 @@
 +#include "Python.h"
 +#include "opcode.h"
 +
 +  }
 +
 +  void
++  JITFasterFBuilder::SetBailBlockId(int v)
++  {
++    // TODO: Implement Me!
++  }
++
++  void
++  JITFasterFBuilder::SetBailOpcodeId(int v)
++  {
++    // TODO: Implement Me!
++  }
++
++  void
 +  JITFasterFBuilder::CreateBailBr()
 +  {
 +    this->builder_.CreateBr(this->bail_block_);
 +    this->bail_block_ = this->state_->CreateBasicBlock("bail_block");
 +    this->builder_.SetInsertPoint(this->bail_block_);
 +
-+    this->lasti_store_ =
-+      this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
-+                                             NULL, "lasti");
-+    Value *f_lasti = FrameTy::f_lasti(this->builder_, this->frame_);
-+    Value *lasti = this->builder_.CreateLoad(this->lasti_store_);
-+    this->builder_.CreateStore(lasti, f_lasti);
-+
++    {
++      this->lasti_store_ =
++        this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
++                                               NULL, "lasti");
++      Value *f_lasti = FrameTy::f_lasti(this->builder_, this->frame_);
++      Value *lasti = this->builder_.CreateLoad(this->lasti_store_);
++      this->builder_.CreateStore(lasti, f_lasti);
++    }
++
++    {
++      this->blockid_store_ =
++        this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
++                                               NULL, "blockid");
++      Value *blockid = this->builder_.CreateLoad(this->blockid_store_);
++      Value *f_bail_blockid = FrameTy::f_bail_blockid(this->builder_, this->frame_);
++      this->builder_.CreateStore(blockid, f_bail_blockid);
++    }
++
++    {
++      this->opcodeid_store_ =
++        this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
++                                               NULL, "opcodeid");
++      Value *opcodeid = this->builder_.CreateLoad(this->opcodeid_store_);
++      Value *f_bail_opcodeid = FrameTy::f_bail_opcodeid(this->builder_, this->frame_);
++      this->builder_.CreateStore(opcodeid, f_bail_opcodeid);
++    }
 +
 +    this->bail_reason_ =
 +      this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
 +  }
 +
 +  void
++  JITFrameFBuilder::SetBailBlockId(int v)
++  {
++    this->builder_.CreateStore(
++      ConstantInt::getSigned(Type::getInt32Ty(this->context_), v),
++      this->blockid_store_);
++  }
++
++  void
++  JITFrameFBuilder::SetBailOpcodeId(int v)
++  {
++    this->builder_.CreateStore(
++      ConstantInt::getSigned(Type::getInt32Ty(this->context_), v),
++      this->opcodeid_store_);
++  }
++
++  void
 +  JITFrameFBuilder::CreateBailBr()
 +  {
 +    this->builder_.CreateBr(this->bail_block_);
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_fbuilder.h
-@@ -0,0 +1,211 @@
+@@ -0,0 +1,219 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_FBUILDER_H_
 +#define PYTHON_JIT_FBUILDER_H_
 +
 +    virtual void SetLastI(int v) = 0;
 +    virtual void SetBailReason(int v) = 0;
++    virtual void SetBailBlockId(int v) = 0;
++    virtual void SetBailOpcodeId(int v) = 0;
 +
 +    virtual void WriteFrameBail(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals) = 0;
 +    virtual void CreateBailBr() = 0;
 +
 +    void SetLastI(int v);
 +    void SetBailReason(int v);
++    void SetBailBlockId(int v);
++    void SetBailOpcodeId(int v);
 +    void CreateBailBr();
 +    void CreateEntryBr();
 +
 +
 +    void SetLastI(int v);
 +    void SetBailReason(int v);
++    void SetBailBlockId(int v);
++    void SetBailOpcodeId(int v);
 +    void CreateBailBr();
 +    void CreateEntryBr();
 +
 +    llvm::Value *builtins_;
 +    llvm::Value *names_;
 +
++    llvm::Value *blockid_store_;
++    llvm::Value *opcodeid_store_;
 +    llvm::Value *lasti_store_;
 +    llvm::Value *bail_reason_;
 +    llvm::BasicBlock *bail_block_;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_fstate.h
-@@ -0,0 +1,150 @@
+@@ -0,0 +1,160 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_FSTATE_H_
 +#define PYTHON_JIT_FSTATE_H_
 +#include "llvm/Support/TargetFolder.h"
 +#include "llvm/ADT/Twine.h"
 +
++#include <unordered_map>
++
 +namespace llvm {
 +  class Module;
 +  class Function;
 +}
 +
 +namespace jit {
++  class JITBasicBlock;
++
 +  llvm::CallInst *
 +  TransferAttributes(llvm::CallInst *callsite, const llvm::Value* callee);
 +
 +        llvm::Value *array_size,
 +        const char *name);
 +
++    std::unordered_map<JITBasicBlock*, llvm::BasicBlock*> &block_map() {
++      return block_map_;
++    }
++
 +  private:
 +    PyGlobalJITData *jit_data_;
 +    llvm::LLVMContext &context_;
 +
 +    llvm::Function *function_;
 +    BuilderT builder_;
++
++    std::unordered_map<JITBasicBlock*, llvm::BasicBlock*> block_map_;
 +  };
 +
 +}
 +  /* printf("OI: %lX\n", (unsigned long)(v->ob_type->tp_iternext)); */
 +  /* printf("OI: %s\n", v->ob_type->tp_name); */
 +  /* printf("OI: %lX\n", v); */
-+  printf("OI: %d ", lasti);
++  printf("OpI: %d ", lasti);
 +  PyObject_Print(v, stdout, 0);
 +  printf("\n");
 +}
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_opcode.cc
-@@ -0,0 +1,675 @@
+@@ -0,0 +1,769 @@
 +#include "Python.h"
 +#include "opcode.h"
 +
 +namespace jit {
 +
 +  void
++  JITBasicFunction::emit(JITFunctionBuilder &fbuilder)
++  {
++    for (auto val : loaded_stack_) {
++      val->emit(fbuilder);
++    }
++    for (auto val : loaded_locals_) {
++      val->emit(fbuilder);
++    }
++
++    auto fstate = fbuilder.getState();
++    for(auto block : blocks_) {
++      auto bb = fstate->CreateBasicBlock("jit_block");
++      fstate->block_map().insert(std::make_pair(block, bb));
++    }
++
++    auto &builder = fbuilder.builder();
++    auto entry_bb = fstate->block_map()[entry_];
++    builder.CreateBr(entry_bb);
++
++    for(auto block : blocks_) {
++      auto block_bb = fstate->block_map()[block];
++      builder.SetInsertPoint(block_bb);
++      block->emit(fbuilder);
++    }
++  }
++
++  void
 +  JITStackValue::emit(JITFunctionBuilder &builder)
 +  {
 +    value_ = builder.Pop();
 +  }
 +
 +  void
++  JITGuardTrueSplit::emit(JITFunctionBuilder &fbuilder)
++  {
++    JITFunctionState::BuilderT &builder = fbuilder.builder();
++    JITFunctionState *state = fbuilder.getState();
++
++    llvm::BasicBlock *trace_true = state->CreateBasicBlock("trace_cont_true");
++    llvm::BasicBlock *trace_false = state->CreateBasicBlock("trace_cont_false");
++    llvm::BasicBlock *check_false = state->CreateBasicBlock("check_false");
++    llvm::BasicBlock *check_rich = state->CreateBasicBlock("check_rich");
++    llvm::BasicBlock *check_rich2 = state->CreateBasicBlock("check_rich2");
++    llvm::BasicBlock *bail_exc = state->CreateBasicBlock("bail_exc");
++
++    Value *v = arg_->getValue(fbuilder);
++    Value *py_true = state->EmbedPointer<PyObject*>(&_Py_TrueStruct);
++    Value *py_false = state->EmbedPointer<PyObject*>(&_Py_FalseStruct);
++
++    // If v == True, shortcut to true
++    Value *is_py_true = builder.CreateICmpEQ(py_true, v);
++    builder.CreateCondBr(is_py_true,
++                         trace_true, check_false);
++
++    // If v == False, shortcut to false
++    builder.SetInsertPoint(check_false);
++    Value *is_py_false = builder.CreateICmpEQ(py_false, v);
++    builder.CreateCondBr(is_py_false,
++                         trace_false, check_rich);
++
++    // Else call into API
++    builder.SetInsertPoint(check_rich);
++    Value *func = state->GetGlobalFunction<int(PyObject*)>("PyObject_IsTrue");
++    Value *res = state->CreateCall(func, v);
++
++    // if > 0, go true
++    Value *is_gt = builder.CreateICmpSGT(res,
++      ConstantInt::getSigned(Type::getInt32Ty(state->context()), 0));
++
++    builder.CreateCondBr(is_gt, trace_true, check_rich2);
++    builder.SetInsertPoint(check_rich2);
++
++    // if == 0, go false
++    Value *is_eq = builder.CreateICmpEQ(res,
++      ConstantInt::getSigned(Type::getInt32Ty(state->context()), 0));
++    builder.CreateCondBr(is_eq, trace_false, bail_exc);
++
++    builder.SetInsertPoint(bail_exc);
++    // if < 0, exc
++    fbuilder.SetBailReason(TR_EXCEPTION);
++    arg_->DecRef(fbuilder);
++    fbuilder.WriteFrameBail(stack_, locals_);
++    fbuilder.SetLastI(lasti_);
++    fbuilder.CreateBailBr();
++
++    builder.SetInsertPoint(trace_true);
++    arg_->DecRef(fbuilder);
++    auto next_bb = state->block_map()[next_[0]];
++    builder.CreateBr(next_bb);
++
++    builder.SetInsertPoint(trace_false);
++    arg_->DecRef(fbuilder);
++    next_bb = state->block_map()[next_[1]];
++    builder.CreateBr(next_bb);
++
++  }
++
++  void
 +  JITGuardTrue::emit(JITFunctionBuilder &fbuilder)
 +  {
 +    JITFunctionState::BuilderT &builder = fbuilder.builder();
 +  }
 +
 +  const int JITOpcodeInfo::ID = 0;
++  const int JITBlockInfo::ID = 0;
 +  const int JITStackValue::ID = 0;
 +  const int JITLocalValue::ID = 0;
 +  const int JITNullValue::ID = 0;
 +  const int JITGuardNull::ID = 0;
 +  const int JITGuardType::ID = 0;
 +  const int JITGuardTrue::ID = 0;
++  const int JITGuardTrueSplit::ID = 0;
 +  const int JITGuardFalse::ID = 0;
 +  const int JITTraceEnd::ID = 0;
 +  const int JITCallFunction::ID = 0;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_opcode.h
-@@ -0,0 +1,1244 @@
+@@ -0,0 +1,1540 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_OPCODE_H_
 +#define PYTHON_JIT_OPCODE_H_
 +#include "JIT/jit_blackhole.h"
 +#include "JIT/jit_utilities.h"
 +
++#include <memory>
++
 +namespace jit {
 +
 +  class JITOpcode {
 +  public:
++    JITOpcode() {}
++    virtual ~JITOpcode() {}
++
 +    virtual void dump() = 0;
 +    virtual void emit(JITFunctionBuilder &builder) = 0;
 +
 +
 +    virtual ~JITBasicBlock()
 +    {
-+      typedef std::vector<JITOpcode *>::iterator iter_t;
-+      for(iter_t i = opcodes_.begin(), e = opcodes_.end(); i != e; ++i) {
-+        delete *i;
++      for(auto op : opcodes_) {
++        delete op;
 +      }
 +    }
 +
 +
 +    void emit(JITFunctionBuilder &builder)
 +    {
-+      typedef std::vector<JITOpcode *>::iterator iter_t;
-+      for(iter_t i = opcodes_.begin(), e = opcodes_.end(); i != e; ++i) {
-+        (*i)->emit(builder);
++      for(auto op : opcodes_) {
++        op->emit(builder);
 +      }
 +    }
 +
 +    void dump()
 +    {
-+      typedef std::vector<JITOpcode *>::iterator iter_t;
-+      for(iter_t i = opcodes_.begin(), e = opcodes_.end(); i != e; ++i) {
-+        (*i)->dump();
++      for(auto op : opcodes_) {
++        op->dump();
 +      }
 +    }
 +
 +    std::vector<JITOpcode *> opcodes_;
 +  };
 +
-+  class JITBasicFunction {
++  class JITBasicFrame {
++  public:
++    virtual std::vector<JITStackValue *> &stack() = 0;
++    virtual std::vector<JITLocalValue *> &locals() = 0;
++  };
++
++  class JITBasicFunction : public JITBasicFrame {
 +  public:
 +    JITBasicFunction()
 +    {
 +    }
 +    virtual ~JITBasicFunction()
 +    {
-+      typedef std::vector<JITBasicBlock *>::iterator iter_t;
-+      for(iter_t i = blocks_.begin(), e = blocks_.end(); i != e; ++i) {
-+        delete *i;
++      for(auto block : blocks_) {
++        delete block;
 +      }
 +    }
 +
 +      blocks_.push_back(block);
 +    }
 +
-+    void emit(JITFunctionBuilder &builder)
-+    {
-+      assert(blocks_.size() == 1);
-+      typedef std::vector<JITBasicBlock *>::iterator iter_t;
-+      for(iter_t i = blocks_.begin(), e = blocks_.end(); i != e; ++i) {
-+        (*i)->emit(builder);
++    void emit(JITFunctionBuilder &builder);
++
++    void dump()
++    {
++      for (auto block : blocks_) {
++        std::cout << "** BLOCK **\n";
++        block->dump();
 +      }
 +    }
 +
-+    void dump()
-+    {
-+      typedef std::vector<JITBasicBlock *>::iterator iter_t;
-+      for(iter_t i = blocks_.begin(), e = blocks_.end(); i != e; ++i) {
-+        (*i)->dump();
-+      }
++    std::vector<JITStackValue *> &stack()
++    {
++      return loaded_stack_;
++    }
++
++    std::vector<JITLocalValue *> &locals()
++    {
++      return loaded_locals_;
 +    }
 +
 +  private:
-+    JITBasicBlock *preamble_;
 +    JITBasicBlock *entry_;
 +    std::vector<JITBasicBlock *> blocks_;
++
++    std::vector<JITLocalValue *> loaded_locals_;
++    std::vector<JITStackValue *> loaded_stack_;
 +  };
 +
 +  class JITValue : public JITOpcode {
 +
 +  class JITOpcodeInfo : public JITOpcode {
 +  public:
-+    JITOpcodeInfo(int lasti, std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
-+      : lasti_(lasti), stack_(stack), locals_(locals)
++    JITOpcodeInfo(int lasti, int opid,
++                  std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
++      : opid_(opid), lasti_(lasti), stack_(stack), locals_(locals)
 +    {
 +    }
 +
 +    virtual void emit(JITFunctionBuilder &fbuilder)
 +    {
 +      fbuilder.SetLastI(lasti_);
++      fbuilder.SetBailOpcodeId(opid_);
++
++      // JITFunctionState *state = fbuilder.getState();
++      // llvm::Function *func = state->GetGlobalFunction<void(int, PyObject*)>("output_opcodeinfo");
 +      // if (stack_.size() > 0) {
-+      //   JITFunctionState *state = fbuilder.getState();
-+
-+      //   llvm::Function *func = state->GetGlobalFunction<void(int, PyObject*)>("output_opcodeinfo");
 +      //   state->CreateCall(func,
-+      //                     llvm::ConstantInt::getSigned(llvm::Type::getInt32Ty(state->context()), lasti_),
++      //                     llvm::ConstantInt::getSigned(
++      //                         llvm::Type::getInt32Ty(state->context()), lasti_),
 +      //                     stack_.back()->getValue(fbuilder));
 +      // }
++      // else {
++      //   state->CreateCall(func,
++      //                     llvm::ConstantInt::getSigned(
++      //                         llvm::Type::getInt32Ty(state->context()), lasti_),
++      //                     state->GetNull<PyObject *>());
++      // }
 +    }
 +
 +    virtual uintptr_t type()
 +    static const int ID;
 +
 +  private:
++    int opid_;
 +    int lasti_;
 +    std::vector<JITValue *> stack_;
 +    std::vector<JITValue *> locals_;
 +  };
 +
 +
++  class JITBlockInfo : public JITOpcode {
++  public:
++    JITBlockInfo(int blockid) : blockid_(blockid)
++    {
++    }
++    virtual ~JITBlockInfo() {}
++
++    virtual void dump()
++    {
++      std::cout << "BLOCK_INFO " << blockid_ << "\n";
++    }
++
++    virtual void emit(JITFunctionBuilder &fbuilder)
++    {
++      fbuilder.SetBailBlockId(this->blockid_);
++    }
++
++    virtual uintptr_t type()
++    {
++      return reinterpret_cast<uintptr_t>(&ID);
++    }
++    static const int ID;
++
++  private:
++    int blockid_;
++  };
++
 +  class JITLocalValue : public JITValue {
 +  public:
 +    JITLocalValue(int num)
 +      delete type_;
 +    }
 +
++    int number()
++    {
++      return num_;
++    }
++
 +    virtual void dump()
 +    {
 +      std::cout << "Local Value " << num_ << "\n";
 +    return NULL;
 +  }
 +
++  class JITGuardTrueSplit : public JITOpcode {
++  public:
++    JITGuardTrueSplit(JITValue *arg,
++                      const std::vector<JITBasicBlock *> &next,
++                      int lasti,
++                      std::vector<JITValue *> &stack,
++                      std::vector<JITValue *> &locals)
++      : arg_(arg), next_(next), lasti_(lasti),
++        stack_(stack), locals_(locals)
++    {
++      arg->addUser(this);
++    }
++
++    virtual void dump()
++    {
++      std::cout << "GUARD_TRUE_SPLIT\n";
++    }
++
++    virtual void emit(JITFunctionBuilder &builder);
++
++    virtual uintptr_t type()
++    {
++      return reinterpret_cast<uintptr_t>(&ID);
++    }
++    static const int ID;
++
++  private:
++    JITValue *arg_;
++    std::vector<JITBasicBlock *> next_;
++    int lasti_;
++    std::vector<JITValue *> stack_;
++    std::vector<JITValue *> locals_;
++  };
++
 +  class JITGuardTrue : public JITOpcode {
 +  public:
 +    JITGuardTrue(JITValue *arg, BLACKHOLE reason, int lasti,
 +    std::vector<JITValue *> stack_;
 +    std::vector<JITValue *> locals_;
 +  };
++
++  class JITOpBuilder {
++  public:
++    JITOpBuilder(JITBasicBlock *block)
++      : block_(block)
++    {}
++    JITOpBuilder(JITBasicFunction *func)
++      : block_(func->getEntryBlock())
++    {}
++
++    virtual ~JITOpBuilder() {}
++
++    JITOpcodeInfo *createOpcodeInfo(int lasti, int opid,
++                                    JITStack &stack, JITLocals &locals)
++    {
++      JITOpcodeInfo *r = new JITOpcodeInfo(lasti, opid, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITBlockInfo *createBlockInfo(int blockid)
++    {
++      JITBlockInfo *r = new JITBlockInfo(blockid);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITCallFunction *createCallFunction(JITValue *func, std::vector<JITValue *> &args,
++                                        JITStack &stack, JITLocals &locals)
++    {
++      JITCallFunction *r = new JITCallFunction(func, args, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITCallFasterFunction *
++    createCallFasterFunction(JITValue *func, PyCodeObject *code,
++                             JITBasicFunction *bfunc,
++                             std::vector<JITValue *> &args,
++                             JITStack &stack, JITLocals &locals)
++    {
++      JITCallFasterFunction *r =
++        new JITCallFasterFunction(func, code,
++                                  bfunc, args,
++                                  stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITMethodGetSelf *
++    createMethodGetSelf(JITValue *arg)
++    {
++      JITMethodGetSelf *r = new JITMethodGetSelf(arg);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITMethodGetFunc *
++    createMethodGetFunc(JITValue *arg)
++    {
++      JITMethodGetFunc *r = new JITMethodGetFunc(arg);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITExtractValue *
++    createExtractValue(JITValue *arg, PyTypeObject *pytype=NULL)
++    {
++      JITExtractValue *r = new JITExtractValue(arg, pytype);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITForIter *createForIter(JITValue *v)
++    {
++      JITForIter *r = new JITForIter(v);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITGenericBinOp *createGenericBinOp(BinaryOpImpl *impl, bool inplace, JITValue *v, JITValue *w)
++    {
++      JITGenericBinOp *r = new JITGenericBinOp(impl, inplace, v, w);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITCompareOp *createCompareOp(JITValue *v, JITValue *w, int oparg)
++    {
++      JITCompareOp *r = new JITCompareOp(v, w, oparg);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITGuardNull *createGuardNull(JITValue *v, BLACKHOLE reason, int lasti, JITStack &stack, JITLocals &locals)
++    {
++      JITGuardNull *r = new JITGuardNull(v, reason, lasti, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITGuardTrue *createGuardTrue(JITValue *v, BLACKHOLE reason, int lasti, JITStack &stack, JITLocals &locals)
++    {
++      JITGuardTrue *r = new JITGuardTrue(v, reason, lasti, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITGuardTrueSplit *createGuardTrueSplit(JITValue *v,
++                                            const std::vector<JITBasicBlock *> &next,
++                                            int lasti, JITStack &stack,
++                                            JITLocals &locals)
++    {
++      auto r = new JITGuardTrueSplit(v, next, lasti, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITGuardFalse *createGuardFalse(JITValue *v, BLACKHOLE reason, int lasti, JITStack &stack, JITLocals &locals)
++    {
++      JITGuardFalse *r = new JITGuardFalse(v, reason, lasti, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITGuardType *createGuardType(JITValue *v, PyTypeObject *type, BLACKHOLE reason, int lasti, JITStack &stack, JITLocals &locals)
++    {
++      JITGuardType *r = new JITGuardType(v, type, reason, lasti, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITLoadConst *createLoadConst(int oparg)
++    {
++      JITLoadConst *r = new JITLoadConst(oparg);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITLoadGlobal *createLoadGlobal(int oparg)
++    {
++      JITLoadGlobal *r = new JITLoadGlobal(oparg);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITNullValue *createNullValue()
++    {
++      JITNullValue *r = new JITNullValue();
++      block_->push_back(r);
++      return r;
++    }
++
++    JITLoadAttr *createLoadAttr(JITValue *v, int oparg)
++    {
++      JITLoadAttr *r = new JITLoadAttr(v, oparg);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITStoreAttr *createStoreAttr(JITValue *target, JITValue *arg, int oparg,
++                                  JITStack &stack, JITLocals &locals)
++    {
++      JITStoreAttr *r = new JITStoreAttr(target, arg, oparg, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITStoreSubscr *createStoreSubscr(JITValue *v0, JITValue *v1, JITValue *v2,
++                                      JITStack &stack, JITLocals &locals)
++    {
++      JITStoreSubscr *r = new JITStoreSubscr(v0, v1, v2, stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITIncRef *createIncRef(JITValue *v)
++    {
++      JITIncRef *r = new JITIncRef(v);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITDecRef *createDecRef(JITValue *v)
++    {
++      JITDecRef *r = new JITDecRef(v);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITXDecRef *createXDecRef(JITValue *v)
++    {
++      JITXDecRef *r = new JITXDecRef(v);
++      block_->push_back(r);
++      return r;
++    }
++
++    JITTraceEnd *createTraceEnd(JITStack &stack, JITLocals &locals)
++    {
++      JITTraceEnd *r = new JITTraceEnd(stack.stack, locals.locals);
++      block_->push_back(r);
++      return r;
++    }
++
++  private:
++    JITBasicBlock *block_;
++  };
++
 +}
 +
 +#endif // PYTHON_JIT_OPCODE_H_
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_tracer.cc
-@@ -0,0 +1,815 @@
+@@ -0,0 +1,880 @@
 +#include "Python.h"
 +#include "opcode.h"
 +
 +#include "JIT/jit_tracer.h"
 +
 +#include "llvm/ExecutionEngine/ExecutionEngine.h"
++#include "llvm/Support/ManagedStatic.h"
++#include "llvm/Support/raw_ostream.h"
 +
 +#include <iostream>
-+
++#include <algorithm>
++
++namespace jit {
++
++  enum JIT_VERIFY_STATUS {
++    VERIFY_OK = 0,
++    VERIFY_ERROR = 1,
++    VERIFY_SILENT_ERROR = 2
++  };
++
++
++  class CodeGenTracker {
++  public:
++    ~CodeGenTracker()
++    {
++      using llvm::errs;
++      errs() << "\nCodeGen Statistics:\n";
++      errs() << "# Primary: " << primary_ << "\n";
++      errs() << "# Bail: " << frombails_ << "\n";
++    }
++
++    void primary() { ++primary_; }
++    void bail() { ++frombails_; }
++
++  private:
++    int primary_;
++    int frombails_;
++  };
++
++  static llvm::ManagedStatic<CodeGenTracker> cg_tracker;
++}
 +
 +PyJITTracer *
 +PyJITTracer_New()
 +
 +PyJITTracer::~PyJITTracer()
 +{
-+  typedef std::set<PyObject*>::iterator iter_t;
-+  for(iter_t iter = funcs_.begin(), end = funcs_.end(); iter != end; ++iter) {
-+    Py_DECREF(*iter);
++  for (auto &func : funcs_) {
++    Py_DECREF(func);
 +  }
 +  funcs_.clear();
 +}
 +
-+enum JIT_VERIFY_STATUS {
-+  VERIFY_OK = 0,
-+  VERIFY_ERROR = 1,
-+  VERIFY_SILENT_ERROR = 2
-+};
-+
-+// Check recursivly if trace is well-formed (no recursive calls) and contains
-+// only supported opcodes. This should be very conservative. If anything looks
-+// fishy throw the trace away.
-+static int
-+verify_trace(std::vector<TraceEntry>::iterator &iter,
-+             std::vector<TraceEntry>::iterator &end,
-+             bool inlined=false)
++#ifdef Py_DEBUG
++#define JIT_COMPILE_TIME
++#endif
++
++void
++PyJITTracer::do_trace(PyCodeObject *code, size_t start)
 +{
-+  for (; iter != end; ++iter) {
++  std::vector<TraceEntry> cut_trace(trace_.begin() + start, trace_.end());
++
++  if (cut_trace[0].opcode == JIT_CALL) {
++    do_trace_on_bail(code, cut_trace);
++    return;
++  }
++
++#ifdef JIT_COMPILE_TIME
++  _PyTime_timeval t;
++  _PyTime_gettimeofday(&t);
++  double t0 = (double)t.tv_sec + t.tv_usec * 1e-6;
++#endif
++
++  jit::JITTraceRoot *root = new jit::JITTraceRoot();
++  jit::JITTraceContainer *part = new jit::JITTraceContainer();
++  part->entries = cut_trace;
++  root->add_part(part);
++  int verify_result = root->verify();
++
++  if (verify_result != jit::VERIFY_OK) {
++    if (verify_result != jit::VERIFY_SILENT_ERROR)
++      std::cout << "Trace contains unkown opcodes\n";
++    else
++      std::cout << "Trace invalid\n";
++    unsuspend();
++    return;
++  }
++
++  // root->dump();
++
++  jit::JITBasicFunction *bfunc = root->analyse();
++  assert(bfunc != NULL);
++
++  jit::JITFunctionState state(PyGlobalJITData::Get());
++  jit::JITFrameFBuilder builder(&state);
++  bfunc->emit(builder);
++
++#ifdef JIT_COMPILE_TIME
++  {
++    _PyTime_gettimeofday(&t);
++    double te = (double)t.tv_sec + t.tv_usec * 1e-6;
++    std::cout << "Generate-time: " << te - t0 << "\n";
++    t0 = te;
++  }
++#endif
++
++  // state.function()->dump();
++  PyGlobalJITData::Get()->optimize(state.function());
++  // state.function()->dump();
++
++#ifdef JIT_COMPILE_TIME
++  {
++    std::cout << "# BasicBlock "
++              << state.function()->getBasicBlockList().size()
++              << "\n";
++  }
++#endif
++
++  if (code->co_jit == NULL) {
++    int codesize = PyBytes_GET_SIZE(code->co_code);
++    code->co_jit = new _JITCode();
++    code->co_jit->mask.resize(codesize / 8 + 1);
++  }
++
++  typedef int(*pyfunc_t)(PyFrameObject*);
++  pyfunc_t trace_func =
++    (pyfunc_t)(PyGlobalJITData::Get()->getExecutionEngine()->getPointerToFunction(state.function()));
++  _JITFunction func;
++  func.func = state.function();
++  func.trace = trace_func;
++  func.opcode = cut_trace[0].pc;
++  func.root = root;
++
++  int offset = func.opcode / 8;
++  int idx = 1 << (func.opcode % 8);
++
++  code->co_jit->mask[offset] |= idx;
++  code->co_jit->funcs.push_back(func);
++
++  jit::cg_tracker->primary();
++
++#ifdef JIT_COMPILE_TIME
++  {
++    _PyTime_gettimeofday(&t);
++    double te = (double)t.tv_sec + t.tv_usec * 1e-6;
++    std::cout << "Compile-time: " << te - t0 << "\n";
++  }
++#endif
++}
++
++void
++PyJITTracer::do_trace_on_bail(PyCodeObject *code,
++                              std::vector<TraceEntry>& cut_trace)
++{
++#ifdef JIT_COMPILE_TIME
++  _PyTime_timeval t;
++  _PyTime_gettimeofday(&t);
++  double t0 = (double)t.tv_sec + t.tv_usec * 1e-6;
++#endif
++
++  if (code->co_jit == NULL) {
++    return;
++  }
++
++  // std::cout << "<---\n";
++  // for(size_t i = 0; i < cut_trace.size(); ++i) {
++  //   std::cout << cut_trace[i] << "\n";
++  // }
++  // std::cout << "--->\n";
++
++  int offset = cut_trace[0].pc;
++  int idx = 1 << (cut_trace[0].pc % 8);
++  if ((code->co_jit->mask[offset] & idx) != 0) {
++    return;
++  }
++
++  _JITFunction *func = NULL;
++  for (auto &f : code->co_jit->funcs) {
++    if (f.opcode == cut_trace[0].pc) {
++      func = &f;
++      break;
++    }
++  }
++
++  if (func == NULL) {
++    return;
++  }
++
++  if (cut_trace[0].opcode != JIT_CALL || cut_trace[1].opcode != JIT_BAIL) {
++    return;
++  }
++
++  TraceEntry b = cut_trace[1];
++  long bail_block = reinterpret_cast<long>(b.arg0);
++  long bail_opcode = reinterpret_cast<long>(b.arg1);
++
++  jit::JITTraceRoot *root = func->root;
++  jit::JITTraceContainer *src_part = root->get_part(bail_block);
++
++  assert(src_part != NULL);
++  assert(src_part->entries[bail_opcode].opcode == POP_JUMP_IF_FALSE);
++
++  root = root->copy();
++  src_part = root->get_part(bail_block);
++
++  auto old_part = root->split(src_part, bail_opcode);
++  auto new_part = new jit::JITTraceContainer();
++  root->add_part(new_part);
++  src_part->next.push_back(new_part);
++
++  assert(old_part->entries[0].opcode != POP_JUMP_IF_FALSE);
++  assert(src_part->entries.back().opcode == POP_JUMP_IF_FALSE);
++
++  new_part->entries.insert(new_part->entries.end(),
++                           cut_trace.begin() + 2, cut_trace.end() - 1);
++
++  // std::cout << "BAIL GENERATE " << bail_block << " " << bail_opcode
++  //           << "\n";
++  int verify_result = root->verify();
++  assert(verify_result == jit::VERIFY_OK);
++
++  // root->dump();
++
++  jit::JITBasicFunction *bfunc = root->analyse();
++  assert(bfunc != NULL);
++
++  jit::JITFunctionState state(PyGlobalJITData::Get());
++  jit::JITFrameFBuilder builder(&state);
++  bfunc->emit(builder);
++
++#ifdef JIT_COMPILE_TIME
++  {
++    _PyTime_gettimeofday(&t);
++    double te = (double)t.tv_sec + t.tv_usec * 1e-6;
++    std::cout << "Generate-time: " << te - t0 << "\n";
++    t0 = te;
++  }
++#endif
++
++  // state.function()->dump();
++  PyGlobalJITData::Get()->optimize(state.function());
++  // state.function()->dump();
++
++#ifdef JIT_COMPILE_TIME
++  {
++    std::cout << "# BasicBlock "
++              << state.function()->getBasicBlockList().size()
++              << "\n";
++  }
++#endif
++
++  // if (code->co_jit == NULL) {
++  //   int codesize = PyBytes_GET_SIZE(code->co_code);
++  //   code->co_jit = new _JITCode();
++  //   code->co_jit->mask.resize(codesize / 8 + 1);
++  // }
++
++  typedef int(*pyfunc_t)(PyFrameObject*);
++  pyfunc_t trace_func =
++    (pyfunc_t)(PyGlobalJITData::Get()->getExecutionEngine()->getPointerToFunction(state.function()));
++
++  _JITFunction new_func;
++  new_func.func = state.function();
++  new_func.trace = trace_func;
++  new_func.opcode = cut_trace[0].pc;
++  new_func.root = root;
++
++  code->co_jit->mask[offset] |= idx;
++
++  auto &funcs = code->co_jit->funcs;
++  // TODO: Really free those functions!
++  funcs.erase(std::remove_if(funcs.begin(), funcs.end(), [&](_JITFunction & f) {
++                return f.opcode == cut_trace[0].pc;
++              }),
++              funcs.end());
++
++  code->co_jit->funcs.push_back(new_func);
++
++  jit::cg_tracker->bail();
++
++#ifdef JIT_COMPILE_TIME
++  {
++    _PyTime_gettimeofday(&t);
++    double te = (double)t.tv_sec + t.tv_usec * 1e-6;
++    std::cout << "Compile-time: " << te - t0 << "\n";
++  }
++#endif
++
++}
++
++void
++PyJITTracer::trace(PyCodeObject *code,
++                   int pc, int opcode, int oparg)
++{
++  if (!active_)
++    return;
++
++  if (suspended_)
++    return;
++
++  TraceEntry entry = TraceEntry(code, pc, opcode, oparg);
++
++  if (merge_point_) {
++    merge_point_ = false;
++    // if (trace_.size() > 0 && trace_[0].opcode == JIT_CALL) {
++    //   for (auto &o : trace_) {
++    //     std::cout << o << "\n";
++    //   }
++    //   std::cout << "E " << entry << "\n";
++    // }
++    for (size_t i = 0; i < trace_.size(); ++i) {
++      TraceEntry &old = trace_[i];
++      if (entry == old) {
++        // if (trace_.size() > 0 && trace_[0].opcode == JIT_CALL) {
++        // if (trace_.size() > 0) {
++        //   std::cout << trace_[0] << "\n";
++        //   std::cout << entry << "\n";
++        //   std::cout << "yyy\n";
++        // }
++        suspend();
++        // dump();
++        do_trace(code, i);
++        unsuspend();
++        return;
++      }
++    }
++  }
++
++  trace_.push_back(entry);
++
++  if (trace_.size() > 500) {
++    clear();
++    return;
++  }
++}
++
++namespace jit {
++
++  // *******************************
++
++  JITTraceAnalysis::JITTraceAnalysis(JITBasicFunction *func)
++    : stack_counter_(0),
++      function_(func),
++      block_(NULL)
++  {
++    block_ = function_->getEntryBlock();
++  }
++
++  JITTraceAnalysis::~JITTraceAnalysis()
++  {
++  }
++
++  void
++  JITTraceAnalysis::emit(JITFunctionState &state)
++  {
++    JITFrameFBuilder builder(&state);
++    for (size_t i = 0; i < loaded_stack_.size(); ++i) {
++      loaded_stack_[i]->emit(builder);
++    }
++    for (size_t i = 0; i < loaded_locals_.size(); ++i) {
++      loaded_locals_[i]->emit(builder);
++    }
++
++    function_->emit(builder);
++  }
++
++  // void
++  // JITTraceAnalysis::createBinaryOp(bool inplace, JITStack &stack, JITLocals &locals, TraceEntry &entry)
++  // {
++  //   int opcode = entry.opcode;
++  //   JITValue *w = stack.Top();
++  //   JITValue *v = stack.Second();
++  //   if (entry.arg0 != NULL)
++  //     v->registerStaticType(entry.arg0);
++  //   if (entry.arg1 != NULL)
++  //     w->registerStaticType(entry.arg1);
++
++  //   BinaryOpImpl *impl = BinaryOpImpl::create(opcode,
++  //                                             entry.arg0, entry.arg1,
++  //                                             stack, locals);
++  //   assert(impl != NULL);
++
++
++  //   if (impl->inlined()) {
++  //     if (!hasTypeGuard(v)) {
++  //       this->createGuardType(v, entry.arg0, BH_NO_BLACKHOLE, entry.pc,
++  //                             stack, locals);
++  //     }
++
++  //     if (!hasTypeGuard(w)) {
++  //       this->createGuardType(w, entry.arg1, BH_NO_BLACKHOLE, entry.pc,
++  //                             stack, locals);
++  //     }
++  //     v = this->createExtractValue(v);
++  //     w = this->createExtractValue(w);
++  //   }
++
++  //   stack.Pop();
++  //   stack.Pop();
++
++  //   JITValue *x = this->createGenericBinOp(impl, inplace, v, w);
++
++  //   assert(x != NULL);
++  //   if (!hasNullGuard(x)) {
++  //     this->createGuardNull(x, BH_BINARY_OP_FAIL, entry.pc, stack, locals);
++  //   }
++  //   stack.Push(x);
++  // }
++
++  // bool
++  // JITTraceAnalysis::createCallFunctionOp(JITValue *func,
++  //                                        std::vector<JITValue*> args,
++  //                                        JITStack &stack, JITLocals &locals,
++  //                                        std::vector<TraceEntry>::iterator &iter,
++  //                                        std::vector<TraceEntry>::iterator &end)
++  // {
++  //   int oparg = iter->oparg;
++  //   int na = oparg & 0xff;
++  //   int nk = (oparg>>8) & 0xff;
++  //   int n = na + 2 * nk;
++
++  //   std::vector<TraceEntry>::iterator next = iter + 1;
++  //   PyObject *py_func = (PyObject*)(iter->arg0);
++  //   PyCodeObject *py_code = NULL;
++  //   PyObject *py_method = NULL;
++
++  //   if (next->opcode != JIT_ENTER_FUNC || py_func == NULL)
++  //     return false;
++
++  //   if (PyMethod_Check(py_func) && PyMethod_GET_SELF(py_func) != NULL) {
++  //     py_method = py_func;
++  //     // PyObject *self = PyMethod_GET_SELF(py_method);
++  //     py_func = PyMethod_GET_FUNCTION(py_method);
++  //     if (py_func == NULL || !PyFunction_Check(py_func))
++  //       return false;
++  //     ++n; // self
++  //     ++na;
++  //   }
++  //   else if (PyFunction_Check(py_func)) {
++  //   }
++  //   else {
++  //     return false;
++  //   }
++
++  //   py_code = (PyCodeObject *)PyFunction_GET_CODE(py_func);
++  //   PyObject *argdefs = PyFunction_GET_DEFAULTS(py_func);
++  //   if (argdefs != NULL || py_code->co_argcount != n ||
++  //       py_code->co_kwonlyargcount != 0 || nk != 0) {
++  //     return false;
++  //   }
++
++  //   if (py_code->co_flags != (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE) &&
++  //       py_code->co_flags != (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE | CO_NESTED)) {
++  //     return false;
++  //   }
++
++  //   if (py_method == NULL) {
++  //       this->createGuardType(func, &PyFunction_Type, BH_NO_BLACKHOLE,
++  //                             iter->pc, stack, locals);
++  //   }
++  //   else {
++  //     this->createGuardType(func, &PyMethod_Type, BH_NO_BLACKHOLE,
++  //                           iter->pc, stack, locals);
++  //     JITValue *self = this->createMethodGetSelf(func);
++  //     this->createGuardNull(self, BH_NO_BLACKHOLE, iter->pc, stack, locals);
++  //     JITValue *mfunc = this->createMethodGetFunc(func);
++  //     this->createGuardNull(mfunc, BH_NO_BLACKHOLE, iter->pc, stack, locals);
++  //     this->createGuardType(mfunc, &PyFunction_Type, BH_NO_BLACKHOLE,
++  //                           iter->pc, stack, locals);
++  //     // All Guards OK
++  //     this->createIncRef(mfunc);
++  //     this->createIncRef(self);
++  //     this->createDecRef(func);
++
++  //     args.insert(args.begin(), self);
++  //     func = mfunc;
++  //   }
++
++  //   JITBasicFunction *bfunc = new JITBasicFunction();
++  //   JITTraceAnalysis analysis(bfunc);
++  //   iter = next + 1;
++  //   JITValue *res = analysis.analyseTrace(py_code, func, args, iter, end);
++  //   this->createCallFasterFunction(func, py_code, bfunc,
++  //                                  args, stack, locals);
++  //   assert(iter->opcode == RETURN_VALUE);
++  //   assert((iter + 1)->opcode == JIT_EXIT_FUNC);
++  //   iter += 1;
++
++  //   stack.Push(res);
++
++  //   return true;
++  // }
++
++
++  // void
++  // JITTraceAnalysis::createCallFunctionOp(JITStack &stack, JITLocals &locals,
++  //                                        std::vector<TraceEntry>::iterator &iter,
++  //                                        std::vector<TraceEntry>::iterator &end)
++  // {
++  //   int oparg = iter->oparg;
++
++  //   int na = oparg & 0xff;
++  //   std::vector<JITValue *> args(na, NULL);
++  //   while (--na >= 0) {
++  //     args[na] = stack.Pop();
++  //   }
++  //   JITValue *func = stack.Pop();
++
++  //   if (createCallFunctionOp(func, args, stack, locals, iter, end)) {
++  //     // std::cout << "TEST OK!\n";
++  //     return;
++  //   }
++  //   // else {
++  //   //   std::cout << "TEST Failed!\n";
++  //   // }
++
++  //   std::vector<TraceEntry>::iterator next = iter + 1;
++
++  //   JITValue *res = this->createCallFunction(func, args, stack, locals);
++  //   if (!hasNullGuard(res)) {
++  //     this->createGuardNull(res, BH_EXC_RAISED, iter->pc, stack, locals);
++  //   }
++  //   this->createDecRef(func);
++  //   stack.Push(res);
++
++  //   // If this call goes to a not-inlineable function remove its trace
++  //   if (next->opcode == JIT_ENTER_FUNC) {
++  //     iter = next;
++  //     swallowTrace(iter, end);
++  //   }
++  // }
++
++  // void
++  // JITTraceAnalysis::swallowTrace(std::vector<TraceEntry>::iterator &iter,
++  //                                std::vector<TraceEntry>::iterator &end)
++  // {
++  //   assert(iter->opcode == JIT_ENTER_FUNC);
++  //   ++iter;
++
++  //   for (; iter != end; ++iter) {
++  //     switch(iter->opcode) {
++  //     case CALL_FUNCTION:
++  //       {
++  //         std::vector<TraceEntry>::iterator next = iter + 1;
++  //         if (next->opcode == JIT_ENTER_FUNC) {
++  //           iter = next;
++  //           swallowTrace(iter, end);
++  //         }
++  //         continue;
++  //       }
++
++  //     case JIT_EXIT_FUNC:
++  //       return;
++
++  //     default:
++  //       continue;
++  //     }
++  //   }
++  //   assert(false);
++  // }
++
++  // JITValue *
++  // JITTraceAnalysis::analyseTrace(PyCodeObject *co,
++  //                                JITValue *func,
++  //                                std::vector<JITValue *> args,
++  //                                std::vector<TraceEntry>::iterator &iter,
++  //                                std::vector<TraceEntry>::iterator &end)
++  // {
++  //   JITStack stack;
++  //   JITLocals locals(co->co_nlocals);
++  //   locals.setNoLoad(true);
++
++  //   for(size_t i = 0, e = co->co_nlocals; i < e; ++i) {
++  //     if (i < args.size())
++  //       locals.Store(i, args[i]);
++  //     else
++  //       locals.Store(i, this->createNullValue());
++  //   }
++
++  //   JITValue *res = this->analyseTrace(stack, locals, iter, end, true);
++
++  //   // Clear Locals
++  //   for(size_t i = 0, e = co->co_nlocals; i < e; ++i) {
++  //     JITValue *v = locals.locals[i];
++  //     if (v != NULL) {
++  //       this->createDecRef(v);
++  //     }
++  //   }
++
++  //   this->createDecRef(func);
++
++  //   assert(stack.stack.size() == 0);
++  //   assert(stack.loaded_stack.size() == 0);
++  //   return res;
++  // }
++
++  // JITValue *
++  // JITTraceAnalysis::analyseTrace(std::vector<TraceEntry>::iterator &iter,
++  //                                std::vector<TraceEntry>::iterator &end)
++  // {
++  //   JITStack stack;
++  //   JITLocals locals;
++  //   return this->analyseTrace(stack, locals, iter, end, false);
++  // }
++
++  // JITValue *
++  // JITTraceAnalysis::analyseTrace(JITStack &stack,
++  //                                JITLocals &locals,
++  //                                std::vector<TraceEntry>::iterator &iter,
++  //                                std::vector<TraceEntry>::iterator &end,
++  //                                bool inlined)
++  // {
++  //   for (; iter != end; ++iter) {
++  //     int pc = iter->pc;
++  //     int opcode = iter->opcode;
++  //     int oparg = iter->oparg;
++  //     int flag = iter->flag;
++  //     PyTypeObject* arg0 = iter->arg0;
++  //     PyTypeObject* arg1 = iter->arg1;
++
++  //     this->createOpcodeInfo(pc, stack, locals);
++
++  //     JITValue *w = NULL;
++  //     JITValue *v = NULL;
++  //     JITValue *u = NULL;
++  //     JITValue *x = NULL;
++  //     switch (opcode) {
++
++
++  //     case POP_JUMP_IF_FALSE:
++  //       v = stack.Pop();
++  //       if (flag == TR_STANDARD) {
++  //         this->createGuardTrue(v, BH_JUMP_ARG, pc, stack, locals);
++  //       }
++  //       else {
++  //         this->createGuardFalse(v, BH_NEXT_OPCODE, pc, stack, locals);
++  //       }
++  //       continue;
++
++  //     case CALL_FUNCTION:
++  //       this->createCallFunctionOp(stack, locals, iter, end);
++  //       continue;
++
++  //     case FOR_ITER:
++  //       v = stack.Top();
++  //       x = this->createForIter(v);
++  //       if (!hasNullGuard(x)) {
++  //         this->createGuardNull(x, BH_FOR_ITER_EXC, pc, stack, locals);
++  //       }
++  //       stack.Push(x);
++  //       continue;
++
++  //     case STORE_FAST:
++  //       w = locals.Load(oparg);
++  //       this->createXDecRef(w);
++
++  //       v = stack.Pop();
++  //       if (arg0 != NULL)
++  //         v->registerStaticType(arg0);
++  //       locals.Store(oparg, v);
++  //       continue;
++
++  //     case LOAD_FAST:
++  //       v = locals.Load(oparg);
++  //       if (!hasNullGuard(v)) {
++  //         this->createGuardNull(v, BH_LOAD_FAST_FAIL, pc, stack, locals);
++  //       }
++  //       this->createIncRef(v);
++  //       stack.Push(v);
++  //       continue;
++
++  //     case LOAD_CONST:
++  //       v = this->createLoadConst(oparg);
++  //       this->createIncRef(v);
++  //       stack.Push(v);
++  //       continue;
++
++  //     case LOAD_GLOBAL:
++  //       v = this->createLoadGlobal(oparg);
++  //       if (!hasNullGuard(v)) {
++  //         this->createGuardNull(v, BH_EXC_RAISED, pc, stack, locals);
++  //       }
++  //       this->createIncRef(v);
++  //       stack.Push(v);
++  //       continue;
++
++  //     case LOAD_ATTR:
++  //       v = stack.Pop();
++  //       x = this->createLoadAttr(v, oparg);
++  //       this->createDecRef(v);
++  //       if (!hasNullGuard(x)) {
++  //         this->createGuardNull(x, BH_EXC_RAISED, pc, stack, locals);
++  //       }
++  //       stack.Push(x);
++  //       continue;
++
++  //     case STORE_ATTR:
++  //       v = stack.Pop();
++  //       u = stack.Pop();
++  //       this->createStoreAttr(v, u, oparg, stack, locals);
++  //       this->createDecRef(v);
++  //       this->createDecRef(u);
++  //       continue;
++
++  //     case POP_TOP:
++  //       v = stack.Pop();
++  //       this->createDecRef(v);
++  //       continue;
++
++  //     case ROT_TWO:
++  //       v = stack.Pop();
++  //       w = stack.Pop();
++  //       stack.Push(v);
++  //       stack.Push(w);
++  //       continue;
++
++  //     case ROT_THREE:
++  //       v = stack.Pop();
++  //       w = stack.Pop();
++  //       x = stack.Pop();
++  //       stack.Push(v);
++  //       stack.Push(x);
++  //       stack.Push(w);
++  //       continue;
++
++  //     case DUP_TOP:
++  //       v = stack.Top();
++  //       this->createIncRef(v);
++  //       stack.Push(v);
++  //       continue;
++
++  //     case DUP_TOP_TWO:
++  //       x = stack.Pop();
++  //       this->createIncRef(x);
++  //       w = stack.Pop();
++  //       this->createIncRef(w);