Commits

ebo committed 015624f

Enabled basic function inlining.

Comments (0)

Files changed (1)

 # HG changeset patch
-# Parent 59223da36dec7b53d3e63d2ed747d9720abbe66a
+# Parent 5b0595339c9d275968b9f43562612e5e044018a0
 
 diff --git a/.hgignore b/.hgignore
 --- a/.hgignore
 new file mode 100644
 --- /dev/null
 +++ b/JIT/PyTypeBuilder.h
-@@ -0,0 +1,252 @@
+@@ -0,0 +1,273 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_PYTYPEBUILDER_H_
 +#define PYTHON_PYTYPEBUILDER_H_
 +    DEFINE_FIELD(PyFloatObject, ob_fval)
 +  };
 +
++  template<> class TypeBuilder<PyFunctionObject, false> {
++  public:
++    static StructType *get(llvm::LLVMContext &context) {
++      return cast<StructType>(
++        PyGlobalJITData::Get()->module()->getTypeByName(
++          // Clang's name for the PyFunctionObject struct.
++          "struct.PyFunctionObject"));
++    }
++
++    // DEFINE_OBJECT_HEAD_FIELDS(PyFunctionObject)
++    DEFINE_FIELD(PyFunctionObject, func_code)
++    DEFINE_FIELD(PyFunctionObject, func_globals)
++    DEFINE_FIELD(PyFunctionObject, func_defaults)
++    DEFINE_FIELD(PyFunctionObject, func_closure)
++    DEFINE_FIELD(PyFunctionObject, func_doc)
++    DEFINE_FIELD(PyFunctionObject, func_name)
++    DEFINE_FIELD(PyFunctionObject, func_dict)
++    DEFINE_FIELD(PyFunctionObject, func_weakreflist)
++    DEFINE_FIELD(PyFunctionObject, func_module)
++  };
++
 +}
 +
 +namespace jit {
 new file mode 100644
 --- /dev/null
 +++ b/JIT/global_jit_data.cc
-@@ -0,0 +1,222 @@
+@@ -0,0 +1,190 @@
 +#include "Python.h"
 +
 +#include "osdefs.h"
 +  return llvm::MemoryBuffer::getMemBuffer(module, "", false);
 +}
 +
-+// Searches for the bitcode file holding the Python standard library.
-+// If one is found, returns its contents in a MemoryBuffer.  If not,
-+// dies with a fatal error.
-+// static llvm::MemoryBuffer *
-+// find_stdlib_bc()
-+// {
-+//   llvm::sys::Path path;
-+//   llvm::SmallVector<llvm::StringRef, 8> sys_path;
-+//   const char delim[] = { DELIM, '\0' };
-+//   std::wstring path_obj = Py_GetPath();
-+//   std::string path_obj2(path_obj.begin(), path_obj.end());
-+
-+//   llvm::StringRef(path_obj2.c_str()).split(sys_path, delim);
-+
-+//   for (ssize_t i = 0, size = sys_path.size(); i < size; ++i) {
-+//     llvm::StringRef elem = sys_path[i];
-+//     path = elem;
-+//     path.appendComponent(LIBPYTHON_BC);
-+//     llvm::OwningPtr<llvm::MemoryBuffer> stdlib_file;
-+//     if(!llvm::MemoryBuffer::getFile(path.str(), stdlib_file)) {
-+//       return stdlib_file.take();
-+//     }
-+//   }
-+//   {
-+//     llvm::StringRef elem = "./Modules";
-+//     path = elem;
-+//     path.appendComponent(LIBPYTHON_BC);
-+//     llvm::OwningPtr<llvm::MemoryBuffer> stdlib_file;
-+//     if(!llvm::MemoryBuffer::getFile(path.str(), stdlib_file)) {
-+//       return stdlib_file.take();
-+//     }
-+//   }
-+//   Py_FatalError("Could not find " LIBPYTHON_BC " on sys.path");
-+//   return NULL;
-+// }
-+
 +extern "C" {
 +  PyObject* code_has_jit(PyCodeObject *self);
 +  PyObject* code_dump_jit(PyCodeObject *self);
 +  this->engine_ = llvm::EngineBuilder(this->module_)
 +    .setErrorStr(&error)
 +    .setEngineKind(llvm::EngineKind::JIT)
-+    // .setUseMCJIT(true)
++    .setUseMCJIT(true)
 +    .create();
 +
 +  if (engine_ == NULL) {
 +  this->engine_->DisableLazyCompilation();
 +
 +  this->opt_ = new llvm::FunctionPassManager(this->module_);
++
++#ifdef Py_DEBUG
 +  this->opt_->add(new llvm::TargetData(*engine_->getTargetData()));
 +  // this->opt_->add(PyCreateSingleFunctionInliningPass());
 +  this->opt_->add(llvm::createPromoteMemoryToRegisterPass());
 +  this->opt_->add(llvm::createInstructionCombiningPass());
 +  this->opt_->add(llvm::createCFGSimplificationPass());
 +  this->opt_->add(llvm::createVerifierPass());
-+
-+  // this->opt_->add(new llvm::TargetData(*engine_->getTargetData()));
-+  // this->opt_->add(llvm::createCFGSimplificationPass());
-+  // this->opt_->add(PyCreateSingleFunctionInliningPass());
-+  // this->opt_->add(llvm::createJumpThreadingPass());
-+  // this->opt_->add(llvm::createPromoteMemoryToRegisterPass());
-+  // this->opt_->add(llvm::createInstructionCombiningPass());
-+  // this->opt_->add(llvm::createCFGSimplificationPass());
-+  // this->opt_->add(llvm::createScalarReplAggregatesPass());
-+  // this->opt_->add(llvm::createLICMPass());
-+  // this->opt_->add(llvm::createJumpThreadingPass());
-+  // this->opt_->add(llvm::createGVNPass());
-+  // this->opt_->add(llvm::createSCCPPass());
-+  // this->opt_->add(llvm::createAggressiveDCEPass());
-+  // this->opt_->add(llvm::createCFGSimplificationPass());
-+  // this->opt_->add(llvm::createVerifierPass());
++#else
++  this->opt_->add(new llvm::TargetData(*engine_->getTargetData()));
++  this->opt_->add(llvm::createCFGSimplificationPass());
++  this->opt_->add(PyCreateSingleFunctionInliningPass());
++  this->opt_->add(llvm::createJumpThreadingPass());
++  this->opt_->add(llvm::createPromoteMemoryToRegisterPass());
++  this->opt_->add(llvm::createInstructionCombiningPass());
++  this->opt_->add(llvm::createCFGSimplificationPass());
++  this->opt_->add(llvm::createScalarReplAggregatesPass());
++  this->opt_->add(llvm::createLICMPass());
++  this->opt_->add(llvm::createJumpThreadingPass());
++  this->opt_->add(llvm::createGVNPass());
++  this->opt_->add(llvm::createSCCPPass());
++  this->opt_->add(llvm::createAggressiveDCEPass());
++  this->opt_->add(llvm::createCFGSimplificationPass());
++  this->opt_->add(llvm::createDeadStoreEliminationPass());
++  this->opt_->add(llvm::createVerifierPass());
++#endif
 +}
 +
 +void
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_binop.cc
-@@ -0,0 +1,482 @@
+@@ -0,0 +1,466 @@
 +#include "JIT/jit_binop.h"
 +#include "JIT/jit_types.h"
 +#include "JIT/jit_tracer.h"
 +      builder.CreateCondBr(isnull, bail, trace_cont);
 +
 +      builder.SetInsertPoint(bail);
-+      std::vector<JITValue *> &locals = locals_.locals;
-+      for (size_t i = 0; i < locals.size(); ++i) {
-+        if (locals[i] != NULL)
-+          fbuilder.StoreLocal(i, locals[i]->getStaticType()->getValue(fbuilder, false, false));
-+      }
-+      std::vector<JITValue *> stack = stack_.stack;;
-+      for (size_t i = 0; i < stack.size(); ++i) {
-+        fbuilder.Push(stack[i]->getStaticType()->getValue(fbuilder, false, false));
-+      }
++      fbuilder.WriteFrameBail(stack_.stack, locals_.locals);
 +      fbuilder.SetBailReason(BH_NO_BLACKHOLE);
 +      fbuilder.CreateBailBr();
 +
 +      builder.CreateCondBr(isnull, bail, trace_cont);
 +
 +      builder.SetInsertPoint(bail);
-+      std::vector<JITValue *> &locals = locals_.locals;
-+      for (size_t i = 0; i < locals.size(); ++i) {
-+        if (locals[i] != NULL)
-+          fbuilder.StoreLocal(i, locals[i]->getStaticType()->getValue(fbuilder, false, false));
-+      }
-+      std::vector<JITValue *> &stack = stack_.stack;;
-+      for (size_t i = 0; i < stack.size(); ++i) {
-+        fbuilder.Push(stack[i]->getStaticType()->getValue(fbuilder, false, false));
-+      }
++      fbuilder.WriteFrameBail(stack_.stack, locals_.locals);
 +      fbuilder.SetBailReason(BH_NO_BLACKHOLE);
 +      fbuilder.CreateBailBr();
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_blackhole.cc
-@@ -0,0 +1,73 @@
+@@ -0,0 +1,94 @@
 +#include "Python.h"
 +#include "frameobject.h"
 +#include "opcode.h"
 +
 +#define POP()           (*--(frame->f_stacktop))
 +
++int
++_PyJIT_BlackHoleEval(PyFrameObject *frame, int reason)
++{
++  return jit::PyJIT_BlackHoleEval(frame, reason);
++}
++
 +namespace jit {
 +
 +  int
 +    unsigned char* first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code);
 +    unsigned char* next_instr = first_instr + frame->f_lasti;
 +
++    // std::cout << "BAIL On: " << co << " " << frame->f_lasti << "\n";
++    // if (PyObject *obj = PyErr_Occurred()) {
++    //   PyObject_Print(obj, stdout, 0);
++    //   std::cout << "--\n";
++    // }
++    // else {
++    //   std::cout << "NOERROR\n";
++    // }
++    // std::cout << "Stack size: " << (frame->f_stacktop - frame->f_valuestack)
++    //           << "\n";
++    // for(PyObject **p = frame->f_valuestack; p != frame->f_stacktop; ++p) {
++    //   PyObject_Print(*p, stdout, 0);
++    //   printf("\n");
++    // }
++
 +    int opcode;
 +    int oparg;
 +    PyObject *u, *v, *w;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_blackhole.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,39 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_BLACKHOLE_H_
 +#define PYTHON_JIT_BLACKHOLE_H_
 +
 +#include "JIT/global_jit_data.h"
 +
++extern "C" {
++  int _PyJIT_BlackHoleEval(PyFrameObject *frame, int reason);
++}
++
 +namespace jit {
 +
 +  enum BLACKHOLE {
-+    BH_NO_BLACKHOLE,
++    BH_NO_BLACKHOLE = 0,
 +    BH_BINARY_OP_FAIL,
 +    BH_JUMP_ARG,
 +    BH_EXC_RAISED,
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_env.cc
-@@ -0,0 +1,70 @@
+@@ -0,0 +1,75 @@
 +#include "Python.h"
 +
 +#include "global_jit_data_fwd.h"
 +  }
 +
 +  JITValue *
-+  JITLocals::Load(int num)
++  JITLocals::Load(size_t num)
 +  {
-+    if (static_cast<size_t>(num) >= locals.size()) {
++    if (num >= locals.size()) {
 +      locals.resize(num + 1);
 +    }
 +    if (locals[num] == NULL) {
-+      JITLocalValue *v = new JITLocalValue(num);
-+      locals[num] = v;
-+      loaded_locals.push_back(v);
++      if (!no_load_) {
++        JITLocalValue *v = new JITLocalValue(num);
++        locals[num] = v;
++        loaded_locals.push_back(v);
++      }
++      else {
++        assert(false);
++      }
 +    }
 +    return locals[num];
 +  }
 +
 +  void
-+  JITLocals::Store(int num, JITValue *val)
++  JITLocals::Store(size_t num, JITValue *val)
 +  {
 +    assert(locals.size() > static_cast<size_t>(num));
 +    locals[num] = val;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_env.h
-@@ -0,0 +1,50 @@
+@@ -0,0 +1,55 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_ENV_H_
 +#define PYTHON_JIT_ENV_H_
 +
 +  class JITLocals {
 +  public:
-+    JITLocals(int num)
-+      : locals(num, NULL)
++    JITLocals(int num = 0)
++      : locals(num, NULL), no_load_(false)
 +    {}
 +
-+    JITValue *Load(int);
-+    void Store(int, JITValue *);
++    void setNoLoad(bool no_load) {
++      no_load_ = no_load;
++    }
++
++    JITValue *Load(size_t);
++    void Store(size_t, JITValue *);
 +
 +    std::vector<JITValue *> locals;
 +    std::vector<JITLocalValue *> loaded_locals;
++  private:
++    bool no_load_;
 +  };
 +
-+
 +}
 +
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_fbuilder.cc
-@@ -0,0 +1,184 @@
+@@ -0,0 +1,381 @@
 +#include "Python.h"
 +#include "opcode.h"
 +
 +#include "JIT/jit_fbuilder.h"
 +#include "JIT/jit_blackhole.h"
++#include "JIT/jit_tracer.h"
 +
 +using llvm::Function;
 +using llvm::Value;
 +using llvm::Type;
 +
 +namespace jit {
++
++  JITFasterFBuilder::JITFasterFBuilder(JITFunctionBuilder &parent,
++                                       llvm::BasicBlock *bail_parent,
++                                       llvm::Value *bail_result,
++                                       llvm::Value *code,
++                                       llvm::Value *globals,
++                                       llvm::Value *builtins)
++    : state_(parent.getState()),
++      builder_(state_->builder()),
++      context_(state_->context()),
++      function_(state_->function()),
++      code_(code),
++      globals_(globals),
++      builtins_(builtins),
++      bail_parent_(bail_parent),
++      bail_result_(bail_result)
++  {
++
++    // Export entry block
++    llvm::BasicBlock *entry = this->state_->CreateBasicBlock("entry_inlined");
++    this->builder_.CreateBr(entry);
++    this->builder_.SetInsertPoint(entry);
++
++    names_ = this->builder_.CreateLoad(CodeTy::co_names(this->builder_, this->code_), "names");
++
++    Function *func = this->state_->GetGlobalFunction<PyObject**(PyCodeObject*)>("_PyJIT_GetConstsFromCode");
++    consts_ = this->state_->CreateCall(func, this->code_);
++
++    this->trace_block_ = this->state_->CreateBasicBlock("trace_block");
++    this->builder_.CreateBr(this->trace_block_);
++
++    this->CreateBailBlock();
++
++    this->builder_.SetInsertPoint(this->trace_block_);
++    this->SetBailReason(BH_NO_BLACKHOLE);
++  }
++
++  void
++  JITFasterFBuilder::CreateBailBlock()
++  {
++    this->bail_reason_ =
++      this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
++                                             NULL, "bail_reason");
++    this->bail_frame_ =
++      this->state_->CreateAllocaInEntryBlock(PyTypeBuilder<PyFrameObject*>::get(this->context_),
++                                             NULL, "bail_frame");
++    this->lasti_store_ =
++      this->state_->CreateAllocaInEntryBlock(Type::getInt32Ty(this->context_),
++                                             NULL, "lasti");
++
++    this->bail_block_ = this->state_->CreateBasicBlock("bail_block");
++    this->builder_.SetInsertPoint(this->bail_block_);
++
++    Value *frame = this->builder_.CreateLoad(this->bail_frame_);
++
++    Value *f_lasti = FrameTy::f_lasti(this->builder_, frame);
++    Value *lasti = this->builder_.CreateLoad(this->lasti_store_);
++    this->builder_.CreateStore(lasti, f_lasti);
++
++    Value *bh =
++      state_->GetGlobalFunction<int(PyFrameObject*, int)>("_PyJIT_BlackHoleEval");
++    Value *br =
++      state_->CreateCall(bh, frame,
++                         this->builder_.CreateLoad(this->bail_reason_));
++
++    lasti =
++      this->builder_.CreateSub(this->builder_.CreateLoad(f_lasti),
++                               ConstantInt::getSigned(Type::getInt32Ty(this->context_), 1));
++    this->builder_.CreateStore(lasti, f_lasti);
++
++    Value *ef =
++      state_->GetGlobalFunction<PyObject*(PyFrameObject*, int)>("PyEval_EvalFrameEx");
++    Value *er = state_->CreateCall(ef, frame, br);
++    state_->DecRef(builder_.CreateBitCast(frame,
++                                          PyTypeBuilder<PyObject*>::get(state_->context())));
++
++    this->builder_.CreateStore(er, this->bail_result_);
++    this->builder_.CreateBr(this->bail_parent_);
++  }
++
++  void
++  JITFasterFBuilder::SetLastI(int v)
++  {
++    this->builder_.CreateStore(
++      ConstantInt::getSigned(Type::getInt32Ty(this->context_), v),
++      this->lasti_store_);
++  }
++
++  void
++  JITFasterFBuilder::SetBailReason(int v)
++  {
++    this->builder_.CreateStore(
++      ConstantInt::getSigned(Type::getInt32Ty(this->context_), v),
++      this->bail_reason_);
++  }
++
++  void
++  JITFasterFBuilder::CreateBailBr()
++  {
++    this->builder_.CreateBr(this->bail_block_);
++  }
++
++  void
++  JITFasterFBuilder::CreateEntryBr()
++  {
++    this->builder_.CreateBr(this->trace_block_);
++  }
++
++  Value *
++  JITFasterFBuilder::Pop()
++  {
++    assert(false);
++    // May be unneeded
++    // Value *stack_pointer = this->builder_.CreateLoad(this->stack_pointer_addr_);
++    // Value *new_stack_pointer = this->builder_.CreateGEP(stack_pointer,
++    //   ConstantInt::getSigned(Type::getInt32Ty(this->context_), -1));
++    // Value *former_top = this->builder_.CreateLoad(new_stack_pointer);
++    // this->builder_.CreateStore(new_stack_pointer, this->stack_pointer_addr_);
++    // return former_top;
++
++    return NULL;
++  }
++
++  void
++  JITFasterFBuilder::Push(Value *value)
++  {
++    Value *frame = this->builder_.CreateLoad(this->bail_frame_);
++    Value *f_stacktop = FrameTy::f_stacktop(this->builder_, frame);
++    Value *stack_pointer =
++        this->builder_.CreateLoad(f_stacktop,
++                                  "stack_pointer_from_frame");
++    this->builder_.CreateStore(value, stack_pointer);
++    Value *new_stack_pointer = this->builder_.CreateGEP(
++      stack_pointer, ConstantInt::get(Type::getInt32Ty(this->context_), 1));
++    this->builder_.CreateStore(new_stack_pointer, f_stacktop);
++  }
++
++  void
++  JITFasterFBuilder::StoreLocal(int num, llvm::Value *value)
++  {
++    Value *ptr = this->LocalPtr(num);
++    this->builder_.CreateStore(value, ptr);
++  }
++
++  llvm::Value *
++  JITFasterFBuilder::LoadLocal(int num)
++  {
++    assert(false);
++    // Must work on new frame
++    // Value *ptr = this->LocalPtr(num);
++    // return this->builder_.CreateLoad(ptr);
++
++    return NULL;
++  }
++
++  llvm::Value *
++  JITFasterFBuilder::LocalPtr(int arg)
++  {
++    Value *frame = this->builder_.CreateLoad(this->bail_frame_);
++
++    Value *localsplus = FrameTy::f_localsplus(this->builder_, frame);
++    Value *fastlocals = this->builder_.CreateStructGEP(localsplus, 0, "fastlocals");
++    return this->builder_.CreateGEP(fastlocals,
++      ConstantInt::getSigned(Type::getInt32Ty(this->context_), arg));
++  }
++
++  llvm::Value *
++  JITFasterFBuilder::ConstPtr(int arg)
++  {
++    return this->builder_.CreateGEP(this->consts_,
++      ConstantInt::getSigned(Type::getInt32Ty(this->context_), arg));
++  }
++
++  void
++  JITFasterFBuilder::OutputInfo(Value *v)
++  {
++    Function *func = this->state_->GetGlobalFunction<void(PyObject*)>("output_info");
++    this->state_->CreateCall(func, v);
++  }
++
++  void
++  JITFasterFBuilder::WriteFrameBail(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
++  {
++    Function *func = this->state_->GetGlobalFunction<PyFrameObject*(PyCodeObject*, PyObject*)>("_PyJIT_CreateFrame");
++    Value *frame = this->state_->CreateCall(func, code_, globals_);
++    this->builder_.CreateStore(frame, bail_frame_);
++    for (size_t i = 0; i < locals.size(); ++i) {
++      if (locals[i] != NULL)
++        this->StoreLocal(i, locals[i]->getStaticType()->getValue(*this, false, false));
++    }
++    for (size_t i = 0; i < stack.size(); ++i) {
++      this->Push(stack[i]->getStaticType()->getValue(*this, false, false));
++    }
++  }
++
++
++  // ############################
++
 +  JITFrameFBuilder::JITFrameFBuilder(JITFunctionState *state)
 +    : state_(state),
 +      builder_(state_->builder()),
 +    this->builder_.CreateStore(new_stack_pointer, this->stack_pointer_addr_);
 +  }
 +
-+  Value *
-+  JITFrameFBuilder::Top()
-+  {
-+    Value *stack_pointer = this->builder_.CreateLoad(this->stack_pointer_addr_);
-+    Value *new_stack_pointer = this->builder_.CreateGEP(stack_pointer,
-+      ConstantInt::getSigned(Type::getInt32Ty(this->context_), -1));
-+    Value *top = this->builder_.CreateLoad(new_stack_pointer);
-+    return top;
-+  }
-+
 +  void
 +  JITFrameFBuilder::StoreLocal(int num, llvm::Value *value)
 +  {
 +  JITFrameFBuilder::OutputInfo(Value *v)
 +  {
 +    Function *func = this->state_->GetGlobalFunction<void(PyObject*)>("output_info");
-+    // Value *arg0 = ConstantInt::getSigned(Type::getInt32Ty(this->context_),
-+    //                                      this->lasti_);
-+    // Value *v2 = this->builder_.CreateLoad(ObjectTy::ob_type(this->builder_, v));
 +    this->state_->CreateCall(func, v);
 +  }
 +
++  void
++  JITFrameFBuilder::WriteFrameBail(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
++  {
++    for (size_t i = 0; i < locals.size(); ++i) {
++      if (locals[i] != NULL)
++        this->StoreLocal(i, locals[i]->getStaticType()->getValue(*this, false, false));
++    }
++    for (size_t i = 0; i < stack.size(); ++i) {
++      this->Push(stack[i]->getStaticType()->getValue(*this, false, false));
++    }
++  }
 +}
 diff --git a/JIT/jit_fbuilder.h b/JIT/jit_fbuilder.h
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_fbuilder.h
-@@ -0,0 +1,117 @@
+@@ -0,0 +1,210 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_FBUILDER_H_
 +#define PYTHON_JIT_FBUILDER_H_
 +#include "llvm/Type.h"
 +#include "llvm/Support/IRBuilder.h"
 +
++#include <vector>
++
 +namespace jit {
 +
++  class JITValue;
++
 +  class JITFunctionBuilder {
 +  public:
 +    virtual JITFunctionState::BuilderT &builder() = 0;
 +    virtual JITFunctionState *getState() = 0;
 +
 +    virtual llvm::Value *Pop() = 0;
-+    virtual llvm::Value *Top() = 0;
 +    virtual void Push(llvm::Value *value) = 0;
 +
 +    virtual void StoreLocal(int num, llvm::Value *value) = 0;
 +
 +    virtual void SetLastI(int v) = 0;
 +    virtual void SetBailReason(int v) = 0;
++
++    virtual void WriteFrameBail(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals) = 0;
 +    virtual void CreateBailBr() = 0;
 +    virtual void CreateEntryBr() = 0;
 +
 +    virtual llvm::Value *getGlobals() = 0;
 +    virtual llvm::Value *getBuiltins() = 0;
 +
++    virtual bool isInlined() = 0;
 +  };
 +
-+  class JITFrameFBuilder : public JITFunctionBuilder {
-+    JITFrameFBuilder(const JITFrameFBuilder &);
-+    void operator=(const JITFrameFBuilder &);
++  class JITFasterFBuilder : public JITFunctionBuilder {
++    JITFasterFBuilder(const JITFasterFBuilder &);
++    void operator=(const JITFasterFBuilder &);
 +
 +  public:
-+    JITFrameFBuilder(JITFunctionState *state);
++    JITFasterFBuilder(JITFunctionBuilder &parent,
++                      llvm::BasicBlock *bail_parent,
++                      llvm::Value *bail_result,
++                      llvm::Value *code,
++                      llvm::Value *globals,
++                      llvm::Value *builtins);
 +    JITFunctionState::BuilderT &builder()
 +    {
 +      return builder_;
 +    }
 +
 +    llvm::Value *Pop();
-+    llvm::Value *Top();
 +    void Push(llvm::Value *value);
 +
 +    void StoreLocal(int num, llvm::Value *value);
 +      return builtins_;
 +    }
 +
++    bool isInlined()
++    {
++      return true;
++    }
++
++    virtual void WriteFrameBail(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals);
++
++  private:
++    void CreateBailBlock();
++
++    JITFunctionState *state_;
++    JITFunctionState::BuilderT &builder_;
++    llvm::LLVMContext &context_;
++
++    llvm::Function *function_;
++
++    llvm::Value *code_;
++    llvm::Value *consts_;
++    llvm::Value *globals_;
++    llvm::Value *builtins_;
++    llvm::Value *names_;
++
++    llvm::BasicBlock *bail_parent_;
++    llvm::Value *bail_result_;
++    llvm::Value *lasti_store_;
++    llvm::Value *bail_reason_;
++    llvm::Value *bail_frame_;
++    llvm::BasicBlock *bail_block_;
++
++    llvm::BasicBlock *trace_block_;
++  };
++
++  class JITFrameFBuilder : public JITFunctionBuilder {
++    JITFrameFBuilder(const JITFrameFBuilder &);
++    void operator=(const JITFrameFBuilder &);
++
++  public:
++    JITFrameFBuilder(JITFunctionState *state);
++    JITFunctionState::BuilderT &builder()
++    {
++      return builder_;
++    }
++    JITFunctionState *getState()
++    {
++      return state_;
++    }
++
++    llvm::Value *Pop();
++    void Push(llvm::Value *value);
++
++    void StoreLocal(int num, llvm::Value *value);
++    llvm::Value *LoadLocal(int num);
++
++    void SetLastI(int v);
++    void SetBailReason(int v);
++    void CreateBailBr();
++    void CreateEntryBr();
++
++    void OutputInfo(llvm::Value *v);
++
++    llvm::Value *LocalPtr(int arg);
++    llvm::Value *ConstPtr(int arg);
++
++    llvm::Value *getNames()
++    {
++      return names_;
++    }
++    llvm::Value *getGlobals()
++    {
++      return globals_;
++    }
++    llvm::Value *getBuiltins()
++    {
++      return builtins_;
++    }
++
++    bool isInlined()
++    {
++      return true;
++    }
++
++    virtual void WriteFrameBail(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals);
++
 +  private:
 +    void CreateBailBlock();
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_inline_functions.c
-@@ -0,0 +1,146 @@
+@@ -0,0 +1,167 @@
 +#include "Python.h"
 +#include "frameobject.h"
 +#include "longintrepr.h"
 +{
 +  /* 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: %lX\n", v); */
++  printf("OI: ");
++  PyObject_Print(v, stdout, 0);
++  printf("\n");
 +}
 +
 +double __attribute__((always_inline))
 +  Py_XDECREF(obj);
 +}
 +
++void __attribute__((always_inline))
++_PyJIT_WrapSDecref(PyObject *obj)
++{
++  _Py_DEC_REFTOTAL  _Py_REF_DEBUG_COMMA (obj->ob_refcnt--);
++  _Py_CHECK_REFCNT(obj);
++}
++
 +PyObject ** __attribute__((always_inline))
 +_PyJIT_GetConstsFromCode(PyCodeObject *obj)
 +{
 +  return consts->ob_item;
 +}
 +
++PyFrameObject *
++_PyJIT_CreateFrame(PyCodeObject *co, PyObject *globals)
++{
++  PyThreadState *tstate = PyThreadState_GET();
++  PyFrameObject *f = PyFrame_New(tstate, co, globals, NULL);
++  if (f == NULL)
++    abort();
++
++  return f;
++}
++
 +/* Define a global using PyTupleObject so we can look it up from
 +   TypeBuilder<PyTupleObject>. */
 +PyTupleObject *_dummy_TupleObject;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_tracer.cc
-@@ -0,0 +1,1018 @@
+@@ -0,0 +1,1222 @@
 +#include "Python.h"
 +#include "opcode.h"
 +
 +  funcs_.clear();
 +}
 +
-+static bool
++enum JIT_VERIFY_STATUS {
++  VERIFY_OK = 0,
++  VERIFY_ERROR = 1,
++  VERIFY_SILENT_ERROR = 2
++};
++
++static int
 +verify_trace(std::vector<TraceEntry>::iterator &iter,
 +             std::vector<TraceEntry>::iterator &end,
 +             bool inlined=false)
 +
 +    switch (opcode) {
 +    case JIT_EXIT_FUNC:
-+      return inlined;
++      if (inlined)
++        return VERIFY_OK;
++      else
++        return VERIFY_SILENT_ERROR;
 +
 +    case POP_JUMP_IF_FALSE:
 +      if (flag != TR_STANDARD) {
 +        // if (flag != TR_STANDARD && flag != TR_JUMP_TAKEN) {
-+        return false;
++        return VERIFY_ERROR;
 +      }
 +      break;
 +
 +
 +    case BINARY_SUBSCR:
 +      if (flag != TR_STANDARD) {
-+        return false;
++        return VERIFY_ERROR;
 +      }
 +      break;
 +
 +    case RETURN_VALUE:
 +      {
-+        if (flag != TR_STANDARD) {
-+          return false;
++        if (flag != TR_STANDARD || iter + 1 == end) {
++          return VERIFY_ERROR;
 +        }
-+        if (iter + 1 == end) {
-+          return false;
-+        }
 +
 +        ++iter;
-+        return iter->opcode == JIT_EXIT_FUNC;
++        return iter->opcode == JIT_EXIT_FUNC ? VERIFY_OK : VERIFY_ERROR;
 +      }
 +
 +    case CALL_FUNCTION:
 +      {
 +        if (flag != TR_STANDARD) {
-+          return false;
++          return VERIFY_ERROR;
 +        }
 +
 +        // int na = oparg & 0xff;
 +        int nk = (oparg >> 8) & 0xff;
 +
-+        if (nk > 0)
-+          return false;
++        if (nk > 0) {
++          return VERIFY_ERROR;
++        }
 +
 +        if (iter + 1 == end) {
 +          break;
 +        if (next->opcode == JIT_ENTER_FUNC) {
 +          iter += 2;
 +          bool result = verify_trace(iter, end, true);
-+          if (!result)
-+            return false;
++          if (result != VERIFY_OK)
++            return result;
 +
 +          if (iter == end || iter->opcode != JIT_EXIT_FUNC)
-+            return false;
++            return VERIFY_ERROR;
 +          std::vector<TraceEntry>::iterator prev = iter - 1;
 +          if (prev->opcode != RETURN_VALUE)
-+            return false;
++            return VERIFY_ERROR;
 +        }
 +
 +        break;
 +      default:
 +        std::cout << opcode << "/" << oparg << " ";
 +        std::cout << "(" << pc << " " << opcode << ")";
-+        return false;
++        return VERIFY_ERROR;
 +        break;
 +      }
 +      if (flag != TR_STANDARD) {
-+        return false;
++        return VERIFY_ERROR;
 +      }
 +      break;
 +
++    case JIT_CALL:
++      return VERIFY_SILENT_ERROR;
++
 +    default:
 +      std::cout << "(" << pc << " " << opcode << ")";
-+      return false;
++      return VERIFY_ERROR;
 +      break;
 +    }
 +  }
-+  return !inlined;
++  return inlined ? VERIFY_ERROR : VERIFY_OK;
 +}
 +
++#ifdef Py_DEBUG
 +#define JIT_COMPILE_TIME
++#endif
++
 +void
 +PyJITTracer::do_trace(PyCodeObject *code, size_t start)
 +{
 +  std::vector<TraceEntry> cut_trace(trace_.begin() + start, trace_.end());
 +  std::vector<TraceEntry>::iterator tr_begin = cut_trace.begin();
 +  std::vector<TraceEntry>::iterator tr_end = cut_trace.end();
-+  if (!verify_trace(tr_begin, tr_end)) {
-+    std::cout << "Trace contains unkown opcodes\n";
++  int verify_result = verify_trace(tr_begin, tr_end);
++  if (verify_result != VERIFY_OK) {
++    if (verify_result != VERIFY_SILENT_ERROR)
++      std::cout << "Trace contains unkown opcodes\n";
 +    unsuspend();
 +    return;
 +  }
 +  tr_begin = cut_trace.begin();
 +  tr_end = cut_trace.end();
 +  analysis.analyseTrace(tr_begin, tr_end);
++
 +  // std::cout << "-------------------------------\n";
 +  // analysis.dump();
 +  // std::cout << "-------------------------------\n";
 +  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();
 +    JITValue *x = this->createGenericBinOp(impl, inplace, v, w);
 +
 +    assert(x != NULL);
-+    this->createGuardNull(x, BH_BINARY_OP_FAIL, entry.pc, stack, locals);
++    if (!x->getStaticType()->hasNullGuard()) {
++      x->getStaticType()->setNullGuard(true);
++      this->createGuardNull(x, BH_BINARY_OP_FAIL, entry.pc, stack, locals);
++    }
 +    stack.Push(x);
 +  }
 +
 +                                         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();
++    std::vector<TraceEntry>::iterator next = iter + 1;
++
++    PyObject *py_func = (PyObject*)(iter->arg0);
++    if (next->opcode == JIT_ENTER_FUNC &&
++        py_func != NULL && PyFunction_Check(py_func)) {
++      int na = oparg & 0xff;
++      int nk = (oparg>>8) & 0xff;
++      int n = na + 2 * nk;
++
++      PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(py_func);
++      PyObject *argdefs = PyFunction_GET_DEFAULTS(py_func);
++      if (argdefs == NULL && co->co_argcount == n &&
++          co->co_kwonlyargcount == 0 && nk == 0 &&
++          (co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE) ||
++           co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE | CO_NESTED))) {
++
++        // This may be a double check
++        this->createGuardType(func, &PyFunction_Type, BH_NO_BLACKHOLE,
++                              iter->pc, stack, locals);
++
++        JITTraceAnalysis analysis;
++        iter = next + 1;
++        JITValue *res = analysis.analyseTrace(co, func, args, iter, end);
++        this->createCallFasterFunction(func, co, analysis.trace(),
++                                       args, stack, locals);
++        assert(iter->opcode == RETURN_VALUE);
++        assert((iter + 1)->opcode == JIT_EXIT_FUNC);
++        iter += 1;
++
++        stack.Push(res);
++        return;
++      }
++    }
++
 +    JITValue *res = this->createCallFunction(func, args, stack, locals);
-+    this->createGuardNull(res, BH_EXC_RAISED, iter->pc, stack, locals);
++    if (!res->getStaticType()->hasNullGuard()) {
++      res->getStaticType()->setNullGuard(true);
++      this->createGuardNull(res, BH_EXC_RAISED, iter->pc, stack, locals);
++    }
 +    stack.Push(res);
 +
++    if (next->opcode == JIT_ENTER_FUNC) {
++      iter = next;
++      swallowTrace(iter, end);
++    }
++
 +//     PyObject *py_func = (PyObject*)(iter->arg0);
 +//     std::cout << "EMIT CALL_FUNCTION " << py_func->ob_type->tp_name << "\n";
 +
 +
 +//     }
 +
-+    std::vector<TraceEntry>::iterator next = iter + 1;
-+    if (next->opcode == JIT_ENTER_FUNC) {
-+      iter = next;
-+      swallowTrace(iter, end);
-+    }
-+
 +  }
 +
 +  void
 +    assert(false);
 +  }
 +
-+  void
++  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 = args.size(); i < e; ++i) {
++      locals.Store(i, args[i]);
++    }
++
++    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(0);
++    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;
 +      case FOR_ITER:
 +        v = stack.Top();
 +        x = this->createForIter(v);
-+        this->createGuardNull(x, BH_FOR_ITER_EXC, pc, stack, locals);
++        if (!x->getStaticType()->hasNullGuard()) {
++          x->getStaticType()->setNullGuard(true);
++          this->createGuardNull(x, BH_FOR_ITER_EXC, pc, stack, locals);
++        }
 +        stack.Push(x);
 +        continue;
 +
 +
 +      case LOAD_FAST:
 +        v = locals.Load(oparg);
-+        this->createGuardNull(v, BH_LOAD_FAST_FAIL, pc, stack, locals);
++        if (!v->getStaticType()->hasNullGuard()) {
++          v->getStaticType()->setNullGuard(true);
++          this->createGuardNull(v, BH_LOAD_FAST_FAIL, pc, stack, locals);
++        }
 +        this->createIncRef(v);
 +        stack.Push(v);
 +        continue;
 +
 +      case LOAD_GLOBAL:
 +        v = this->createLoadGlobal(oparg);
-+        this->createGuardNull(v, BH_EXC_RAISED, pc, stack, locals);
++        if (!v->getStaticType()->hasNullGuard()) {
++          v->getStaticType()->setNullGuard(true);
++          this->createGuardNull(v, BH_EXC_RAISED, pc, stack, locals);
++        }
 +        this->createIncRef(v);
 +        stack.Push(v);
 +        continue;
 +        if (arg1 != NULL)
 +          w->registerStaticType(arg1);
 +        x = this->createCompareOp(v, w, oparg);
-+        this->createGuardNull(x, BH_BINARY_OP_FAIL, pc, stack, locals);
++        if (!x->getStaticType()->hasNullGuard()) {
++          x->getStaticType()->setNullGuard(true);
++          this->createGuardNull(x, BH_BINARY_OP_FAIL, pc, stack, locals);
++        }
 +        stack.Push(x);
 +        continue;
 +
 +      case JUMP_ABSOLUTE:
 +        continue;
 +
++      case RETURN_VALUE:
++        if (inlined) {
++          return stack.Pop();
++        }
++
 +      default:
++        std::cout << "Unkown Opcode " << opcode << "\n";
 +        assert(false);
 +      }
 +    }
 +    loaded_locals_ = locals.loaded_locals;
 +    loaded_stack_ = stack.loaded_stack;
 +    stack_counter_ = stack.stack_counter;
++
++    return NULL;
 +  }
 +
 +  void
 +                                   std::vector<JITValue *> &locals)
 +    : func_(func),
 +      args_(args), stack_(stack), locals_(locals),
-+      type_(NULL)
++      type_(new JITOpaqueObject)
 +  {
 +  }
 +
 +    builder.CreateCondBr(state->IsNull(args), bail_args, trace_cont);
 +
 +    builder.SetInsertPoint(bail_args);
-+    for (size_t i = 0; i < locals_.size(); ++i) {
-+      if (locals_[i] != NULL)
-+        fbuilder.StoreLocal(i, locals_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
-+    for (size_t i = 0; i < stack_.size(); ++i) {
-+      fbuilder.Push(stack_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
++
++    fbuilder.WriteFrameBail(stack_, locals_);
 +    fbuilder.Push(func_->getStaticType()->getValue(fbuilder, false, false));
 +    for (size_t i = 0; i < args_.size(); ++i) {
 +      fbuilder.Push(args_[i]->getStaticType()->getValue(fbuilder, false, false));
 +    this->getStaticType()->init(res);
 +  }
 +
++  JITCallFasterFunction::JITCallFasterFunction(JITValue *func,
++                                               PyCodeObject *code,
++                                               std::vector<JITOpcode *> &opcodes,
++                                               std::vector<JITValue *> &args,
++                                               std::vector<JITValue *> &stack,
++                                               std::vector<JITValue *> &locals)
++    : func_(func), code_(code),
++      opcodes_(opcodes), args_(args),
++      stack_(stack), locals_(locals)
++  {
++  }
++
++  void
++  JITCallFasterFunction::emit(JITFunctionBuilder &fbuilder)
++  {
++    JITFunctionState::BuilderT &builder = fbuilder.builder();
++    JITFunctionState *state = fbuilder.getState();
++
++    llvm::BasicBlock *trace_cont = state->CreateBasicBlock("trace_cont");
++    llvm::BasicBlock *bail = state->CreateBasicBlock("bail");
++
++    Value *as_func =
++      builder.CreateBitCast(func_->getValue(fbuilder),
++                            PyTypeBuilder<PyFunctionObject*>::get(state->context()));
++    Value *co = builder.CreateLoad(FunctionTy::func_code(builder, as_func), "code");
++    Value *as_code =
++      builder.CreateBitCast(co,
++                            PyTypeBuilder<PyCodeObject*>::get(state->context()));
++
++    Value *code_type = state->EmbedPointer<PyCodeObject*>(code_);
++
++    Value *check = builder.CreateICmpEQ(as_code, code_type);
++    builder.CreateCondBr(check, trace_cont, bail);
++    builder.SetInsertPoint(trace_cont);
++    trace_cont = state->CreateBasicBlock("trace_cont");
++
++    Value *globals = builder.CreateLoad(FunctionTy::func_globals(builder, as_func),
++                                        "globals");
++
++    // Value *builtins =
++    //   this->state_->CreateAllocaInEntryBlock(PyTypeBuilder<PyObject*>::get(state->context())
++    //                                          NULL, "builtin");
++
++    // If globals are the same, reuse builtins
++    check = builder.CreateICmpEQ(globals, fbuilder.getGlobals());
++    builder.CreateCondBr(check, trace_cont, bail);
++    builder.SetInsertPoint(trace_cont);
++    trace_cont = state->CreateBasicBlock("trace_cont");
++
++    // Check argdefs ?
++    // Check builtins ?
++
++    builder.CreateBr(trace_cont);
++
++    builder.SetInsertPoint(bail);
++    fbuilder.WriteFrameBail(stack_, locals_);
++    fbuilder.Push(func_->getStaticType()->getValue(fbuilder, false, false));
++    for (size_t i = 0; i < args_.size(); ++i) {
++      fbuilder.Push(args_[i]->getStaticType()->getValue(fbuilder, false, false));
++    }
++    fbuilder.SetBailReason(BH_NO_BLACKHOLE);
++    fbuilder.CreateBailBr();
++
++    llvm::Value *bail_result =
++      state->CreateAllocaInEntryBlock(PyTypeBuilder<PyObject*>::get(state->context()),
++                                      NULL, "");
++    llvm::BasicBlock *inline_bail = state->CreateBasicBlock("inline_bail");
++    llvm::BasicBlock *ib_exc = state->CreateBasicBlock("inline_bail_exc");
++    llvm::BasicBlock *ib_ok = state->CreateBasicBlock("inline_bail_ok");
++    llvm::BasicBlock *ib_cont = state->CreateBasicBlock("inline_bail_cont");
++
++    builder.SetInsertPoint(inline_bail);
++    fbuilder.WriteFrameBail(stack_, locals_);
++    llvm::Value *br = builder.CreateLoad(bail_result);
++    builder.CreateCondBr(state->IsNull(br), ib_exc, ib_ok);
++
++    builder.SetInsertPoint(ib_exc);
++    fbuilder.SetBailReason(BH_EXC_RAISED);
++    builder.CreateBr(ib_cont);
++
++    builder.SetInsertPoint(ib_ok);
++    fbuilder.Push(br);
++    fbuilder.SetBailReason(BH_NEXT_OPCODE);
++    builder.CreateBr(ib_cont);
++
++    builder.SetInsertPoint(ib_cont);
++    fbuilder.CreateBailBr();
++
++    builder.SetInsertPoint(trace_cont);
++    JITFasterFBuilder new_builder(fbuilder, inline_bail, bail_result,
++                                  as_code,
++                                  globals, fbuilder.getBuiltins());
++    typedef std::vector<JITOpcode *>::iterator iter_t;
++    for (iter_t iter = opcodes_.begin(), end = opcodes_.end();
++         iter != end; ++iter) {
++      (*iter)->emit(new_builder);
++    }
++  }
++
 +  void
 +  JITCompareOp::emit(JITFunctionBuilder &fbuilder)
 +  {
 +
 +    llvm::Value *ob_type =
 +      builder.CreateLoad(ObjectTy::ob_type(builder, value));
-+    llvm::Value *py_type = state->EmbedPointer<PyTypeObject*>(type->getPyType());
++
++    llvm::Value *py_type = NULL;
++    if (type_ == NULL) {
++       py_type = state->EmbedPointer<PyTypeObject*>(type->getPyType());
++    }
++    else {
++       py_type = state->EmbedPointer<PyTypeObject*>(type_);
++    }
 +    llvm::Value *check = builder.CreateICmpEQ(ob_type, py_type);
 +
 +    builder.CreateCondBr(check, trace_cont, bail);
 +
 +    builder.SetInsertPoint(bail);
-+    for (size_t i = 0; i < locals_.size(); ++i) {
-+      if (locals_[i] != NULL)
-+        fbuilder.StoreLocal(i, locals_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
-+    for (size_t i = 0; i < stack_.size(); ++i) {
-+      fbuilder.Push(stack_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
++    fbuilder.WriteFrameBail(stack_, locals_);
 +    fbuilder.SetLastI(lasti_);
 +    fbuilder.SetBailReason(reason_);
 +    fbuilder.CreateBailBr();
 +                         bail, trace_cont);
 +
 +    builder.SetInsertPoint(bail);
-+    for (size_t i = 0; i < locals_.size(); ++i) {
-+      if (locals_[i] != NULL)
-+        fbuilder.StoreLocal(i, locals_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
-+    for (size_t i = 0; i < stack_.size(); ++i) {
-+      fbuilder.Push(stack_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
++    fbuilder.WriteFrameBail(stack_, locals_);
 +    fbuilder.SetLastI(lasti_);
 +    fbuilder.SetBailReason(reason_);
 +    fbuilder.CreateBailBr();
 +    builder.SetInsertPoint(bail_cont);
 +
 +    arg_->DecRef(fbuilder);
-+    for (size_t i = 0; i < locals_.size(); ++i) {
-+      if (locals_[i] != NULL)
-+        fbuilder.StoreLocal(i, locals_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
-+    for (size_t i = 0; i < stack_.size(); ++i) {
-+      fbuilder.Push(stack_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
++    fbuilder.WriteFrameBail(stack_, locals_);
 +    fbuilder.SetLastI(lasti_);
 +    fbuilder.CreateBailBr();
 +
 +                         trace_cont, bail);
 +
 +    builder.SetInsertPoint(bail);
-+    for (size_t i = 0; i < locals_.size(); ++i) {
-+      if (locals_[i] != NULL)
-+        fbuilder.StoreLocal(i, locals_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
-+    for (size_t i = 0; i < stack_.size(); ++i) {
-+      fbuilder.Push(stack_[i]->getStaticType()->getValue(fbuilder, false, false));
-+    }
++    fbuilder.WriteFrameBail(stack_, locals_);
 +    // Lasti set by opcodeinfo
 +    fbuilder.SetBailReason(BH_EXC_RAISED);
 +    fbuilder.CreateBailBr();
 +  const int JITGuardTrue::ID = 0;
 +  const int JITTraceEnd::ID = 0;
 +  const int JITCallFunction::ID = 0;
++  const int JITCallFasterFunction::ID = 0;
 +
 +  const int JITGenericBinOp::ID = 0;
 +
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_tracer.h
-@@ -0,0 +1,951 @@
+@@ -0,0 +1,1048 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_TRACER_H_
 +#define PYTHON_JIT_TRACER_H_
 +        if (new_type != NULL) {
 +          JITType *old_type = type_;
 +          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
 +          delete old_type;
 +        }
 +      }
 +        if (new_type != NULL) {
 +          JITType *old_type = type_;
 +          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
 +          delete old_type;
 +        }
 +      }
 +        if (new_type != NULL) {
 +          JITType *old_type = type_;
 +          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
 +          delete old_type;
 +        }
 +      }
 +  public:
 +    JITLoadConst(int oparg)
 +      : oparg_(oparg), value_(NULL), type_(new JITOpaqueObject)
-+    {}
++    {
++      type_->setNullGuard(true);
++      type_->setGuard(true);
++    }
 +
 +    ~JITLoadConst()
 +    {
 +
 +    virtual void dump()
 +    {
-+      std::cout << "LOAD_CONST\n";
++      std::cout << "LOAD_CONST " << oparg_ << "\n";
 +    }
 +
 +    virtual void emit(JITFunctionBuilder &builder);
 +          type_ = new_type;
 +          delete old_type;
 +
++          type_->setNullGuard(true);
 +          type_->setGuard(true);
 +        }
 +      }
 +        if (new_type != NULL) {
 +          JITType *old_type = type_;
 +          type_ = new_type;
-+          delete old_type;
-+
-+          type_->setGuard(true);
-+        }
-+      }
-+      else {
-+        if (!type_->matchesType(t)) {
-+          std::cout << "Trace Type mismatch\n";
-+        }
-+      }
-+    }
-+
-+    virtual uintptr_t type()
-+    {
-+      return reinterpret_cast<uintptr_t>(&ID);
-+    }
-+    static const int ID;
-+
-+  private:
-+    int oparg_;
-+    JITType *type_;
-+  };
-+
-+  class JITCallFunction : public JITValue {
-+  public:
-+    JITCallFunction(JITValue *func,
-+                    std::vector<JITValue *> &args,
-+                    std::vector<JITValue *> &stack,
-+                    std::vector<JITValue *> &locals);
-+
-+    ~JITCallFunction()
-+    {
-+      delete type_;
-+    }
-+
-+    virtual void dump()
-+    {
-+      std::cout << "CALL_FUNCTION " << args_.size() << "\n";
-+    }
-+
-+    virtual void emit(JITFunctionBuilder &fbuilder);
-+
-+    virtual llvm::Value *getValue(JITFunctionBuilder &fbuilder) const
-+    {
-+      return getStaticType()->getValue(fbuilder);
-+    }
-+
-+    virtual llvm::Value *getNakedValue(JITFunctionBuilder &fbuilder) const
-+    {
-+      return getStaticType()->getNakedValue(fbuilder);
-+    }
-+
-+    virtual JITType *getStaticType() const
-+    {
-+      return type_;
-+    }
-+
-+    virtual void registerStaticType(const PyTypeObject *t)
-+    {
-+      if (type_ == NULL || type_->canSpecialize(t)) {
-+        JITType *new_type = JITType::createBoxedType(t);
-+        if (new_type != NULL) {
-+          JITType *old_type = type_;
-+          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
 +          delete old_type;
 +        }
 +      }
 +    static const int ID;
 +
 +  private:
-+    JITValue *func_;
-+    std::vector<JITValue *> args_;
-+    std::vector<JITValue *> stack_;
-+    std::vector<JITValue *> locals_;
++    int oparg_;
 +    JITType *type_;
 +  };
 +
-+  class JITGenericBinOp : public JITValue {
++  class JITCallFunction : public JITValue {
 +  public:
-+    JITGenericBinOp(BinaryOpImpl *impl, bool inplace, JITValue *arg0, JITValue *arg1);
-+
-+    ~JITGenericBinOp()
++    JITCallFunction(JITValue *func,
++                    std::vector<JITValue *> &args,
++                    std::vector<JITValue *> &stack,
++                    std::vector<JITValue *> &locals);
++
++    ~JITCallFunction()
 +    {
 +      delete type_;
-+      delete impl_;
 +    }
 +
 +    virtual void dump()
 +    {
-+      std::cout << "GEN_BIN_OP\n";
-+    }
-+
-+    virtual void emit(JITFunctionBuilder &builder);
++      std::cout << "CALL_FUNCTION " << args_.size() << "\n";
++    }
++
++    virtual void emit(JITFunctionBuilder &fbuilder);
 +
 +    virtual llvm::Value *getValue(JITFunctionBuilder &fbuilder) const
 +    {
 +        if (new_type != NULL) {
 +          JITType *old_type = type_;
 +          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
 +          delete old_type;
 +        }
 +      }
 +    static const int ID;
 +
 +  private:
-+    JITValue *arg0_;
-+    JITValue *arg1_;
++    JITValue *func_;
++    std::vector<JITValue *> args_;
++    std::vector<JITValue *> stack_;
++    std::vector<JITValue *> locals_;
 +    JITType *type_;
-+    BinaryOpImpl *impl_;
-+    bool inplace_;
 +  };
 +
-+  class JITCompareOp : public JITValue {
++  class JITCallFasterFunction : public JITOpcode {
 +  public:
-+    JITCompareOp(JITValue *arg0, JITValue *arg1, int oparg)
-+      : arg0_(arg0), arg1_(arg1),
-+        oparg_(oparg), value_(NULL), type_(new JITOpaqueObject)
-+    {
-+    }
-+
-+    ~JITCompareOp()
++    JITCallFasterFunction(JITValue *func,
++                          PyCodeObject *code,
++                          std::vector<JITOpcode *> &opcodes,
++                          std::vector<JITValue *> &args,
++                          std::vector<JITValue *> &stack,
++                          std::vector<JITValue *> &locals);
++
++    ~JITCallFasterFunction()
++    {}
++
++    virtual void dump()
++    {
++      std::cout << "CALL_FUNCTION (Faster) BEGIN\n";
++      typedef std::vector<JITOpcode *>::iterator iter_t;
++      for (iter_t iter = opcodes_.begin(), end = opcodes_.end();
++           iter != end; ++iter) {
++        (*iter)->dump();
++      }
++      std::cout << "CALL_FUNCTION (Faster) END\n";
++    }
++
++    virtual void emit(JITFunctionBuilder &fbuilder);
++
++    virtual uintptr_t type()
++    {
++      return reinterpret_cast<uintptr_t>(&ID);
++    }
++    static const int ID;
++
++  private:
++    JITValue *func_;
++    PyCodeObject *code_;
++    std::vector<JITOpcode *> opcodes_;
++    std::vector<JITValue *> args_;
++    std::vector<JITValue *> stack_;
++    std::vector<JITValue *> locals_;
++  };
++
++  class JITGenericBinOp : public JITValue {
++  public:
++    JITGenericBinOp(BinaryOpImpl *impl, bool inplace, JITValue *arg0, JITValue *arg1);
++
++    ~JITGenericBinOp()
 +    {
 +      delete type_;
++      delete impl_;
 +    }
 +
 +    virtual void dump()
 +    {
-+      std::cout << "COMPARE_OP " << oparg_ << "\n";
++      std::cout << "GEN_BIN_OP\n";
 +    }
 +
 +    virtual void emit(JITFunctionBuilder &builder);
 +
++    virtual llvm::Value *getValue(JITFunctionBuilder &fbuilder) const
++    {
++      return getStaticType()->getValue(fbuilder);
++    }
++
++    virtual llvm::Value *getNakedValue(JITFunctionBuilder &fbuilder) const
++    {
++      return getStaticType()->getNakedValue(fbuilder);
++    }
++
 +    virtual JITType *getStaticType() const
 +    {
 +      return type_;
 +    }
 +
-+    virtual llvm::Value *getValue(JITFunctionBuilder &fbuilder) const
-+    {
-+      return getStaticType()->getValue(fbuilder);
-+    }
-+
-+    virtual llvm::Value *getNakedValue(JITFunctionBuilder &fbuilder) const
-+    {
-+      return getStaticType()->getNakedValue(fbuilder);
-+    }
-+
 +    virtual void registerStaticType(const PyTypeObject *t)
 +    {
 +      if (type_ == NULL || type_->canSpecialize(t)) {
 +        if (new_type != NULL) {
 +          JITType *old_type = type_;
 +          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
 +          delete old_type;
 +        }
 +      }
 +  private:
 +    JITValue *arg0_;
 +    JITValue *arg1_;
++    JITType *type_;
++    BinaryOpImpl *impl_;
++    bool inplace_;
++  };
++
++  class JITCompareOp : public JITValue {
++  public:
++    JITCompareOp(JITValue *arg0, JITValue *arg1, int oparg)
++      : arg0_(arg0), arg1_(arg1),
++        oparg_(oparg), value_(NULL), type_(new JITOpaqueObject)
++    {
++    }
++
++    ~JITCompareOp()
++    {
++      delete type_;
++    }
++
++    virtual void dump()
++    {
++      std::cout << "COMPARE_OP " << oparg_ << "\n";
++    }
++
++    virtual void emit(JITFunctionBuilder &builder);
++
++    virtual JITType *getStaticType() const
++    {
++      return type_;
++    }
++
++    virtual llvm::Value *getValue(JITFunctionBuilder &fbuilder) const
++    {
++      return getStaticType()->getValue(fbuilder);
++    }
++
++    virtual llvm::Value *getNakedValue(JITFunctionBuilder &fbuilder) const
++    {
++      return getStaticType()->getNakedValue(fbuilder);
++    }
++
++    virtual void registerStaticType(const PyTypeObject *t)
++    {
++      if (type_ == NULL || type_->canSpecialize(t)) {
++        JITType *new_type = JITType::createBoxedType(t);
++        if (new_type != NULL) {
++          JITType *old_type = type_;
++          type_ = new_type;
++          type_->setNullGuard(old_type->hasNullGuard());
++          delete old_type;
++        }
++      }
++      else {
++        if (!type_->matchesType(t)) {
++          std::cout << "Trace Type mismatch\n";
++        }
++      }
++    }
++
++    virtual uintptr_t type()
++    {
++      return reinterpret_cast<uintptr_t>(&ID);
++    }
++    static const int ID;
++
++  private:
++    JITValue *arg0_;
++    JITValue *arg1_;
 +    int oparg_;
 +    llvm::Value *value_;
 +    JITType *type_;
 +    JITGuardType(JITValue *arg, BLACKHOLE reason, int lasti,
 +                 std::vector<JITValue *> &stack,
 +                 std::vector<JITValue *> &locals)
++      : arg_(arg), type_(NULL),
++        reason_(reason), lasti_(lasti),
++        stack_(stack), locals_(locals)
++    {}
++
++    JITGuardType(JITValue *arg, PyTypeObject *t, BLACKHOLE reason, int lasti,
++                 std::vector<JITValue *> &stack,
++                 std::vector<JITValue *> &locals)
++      : arg_(arg), type_(t),
++        reason_(reason), lasti_(lasti),
++        stack_(stack), locals_(locals)
++    {}
++
++    virtual void dump()
++    {
++      std::cout << "GUARD_TYPE\n";
++    }
++
++    virtual void emit(JITFunctionBuilder &builder);
++
++    virtual uintptr_t type()
++    {
++      return reinterpret_cast<uintptr_t>(&ID);
++    }
++    static const int ID;
++
++  private:
++    JITValue *arg_;
++    PyTypeObject *type_;
++    BLACKHOLE reason_;
++    int lasti_;
++    std::vector<JITValue *> stack_;
++    std::vector<JITValue *> locals_;
++  };
++
++  class JITGuardNull : public JITOpcode {
++  public:
++    JITGuardNull(JITValue *arg, BLACKHOLE reason, int lasti,
++                 std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
 +      : arg_(arg), reason_(reason), lasti_(lasti),
 +        stack_(stack), locals_(locals)
 +    {}
 +
 +    virtual void dump()
 +    {
-+      std::cout << "GUARD_TYPE\n";
++      std::cout << "GUARD_NULL\n";
 +    }
 +
 +    virtual void emit(JITFunctionBuilder &builder);
 +    std::vector<JITValue *> locals_;
 +  };
 +
-+  class JITGuardNull : public JITOpcode {
++  class JITGuardTrue : public JITOpcode {
 +  public:
-+    JITGuardNull(JITValue *arg, BLACKHOLE reason, int lasti,
++    JITGuardTrue(JITValue *arg, BLACKHOLE reason, int lasti,
 +                 std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
 +      : arg_(arg), reason_(reason), lasti_(lasti),
 +        stack_(stack), locals_(locals)
 +
 +    virtual void dump()
 +    {
-+      std::cout << "GUARD_NULL\n";
++      std::cout << "GUARD_TRUE\n";
 +    }
 +
 +    virtual void emit(JITFunctionBuilder &builder);
 +    std::vector<JITValue *> locals_;
 +  };
 +
-+  class JITGuardTrue : public JITOpcode {
-+  public:
-+    JITGuardTrue(JITValue *arg, BLACKHOLE reason, int lasti,
-+                 std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
-+      : arg_(arg), reason_(reason), lasti_(lasti),
-+        stack_(stack), locals_(locals)
-+    {}
-+
-+    virtual void dump()
-+    {
-+      std::cout << "GUARD_TRUE\n";
-+    }
-+
-+    virtual void emit(JITFunctionBuilder &builder);
-+
-+    virtual uintptr_t type()
-+    {
-+      return reinterpret_cast<uintptr_t>(&ID);
-+    }
-+    static const int ID;
-+
-+  private:
-+    JITValue *arg_;
-+    BLACKHOLE reason_;
-+    int lasti_;
-+    std::vector<JITValue *> stack_;
-+    std::vector<JITValue *> locals_;
-+  };
-+
 +  class JITTraceEnd : public JITOpcode {
 +  public:
 +    JITTraceEnd(std::vector<JITValue *> &stack, std::vector<JITValue *> &locals)
 +
 +    JITTraceAnalysis();
 +
-+    void analyseTrace(std::vector<TraceEntry>::iterator &iter,
-+                      std::vector<TraceEntry>::iterator &end);
++    JITValue *analyseTrace(PyCodeObject *co,
++                           JITValue *func,
++                           std::vector<JITValue *> args,
++                           std::vector<TraceEntry>::iterator &iter,
++                           std::vector<TraceEntry>::iterator &end);
++
++    JITValue *analyseTrace(std::vector<TraceEntry>::iterator &iter,
++                           std::vector<TraceEntry>::iterator &end);
++
++    JITValue *analyseTrace(JITStack &stack,
++                           JITLocals &locals,
++                           std::vector<TraceEntry>::iterator &iter,
++                           std::vector<TraceEntry>::iterator &end,
++                           bool inlined);
 +
 +    void swallowTrace(std::vector<TraceEntry>::iterator &iter,
 +                      std::vector<TraceEntry>::iterator &end);
 +      return r;
 +    }
 +
++    JITCallFasterFunction *
++    createCallFasterFunction(JITValue *func, PyCodeObject *code,
++                             std::vector<JITOpcode *> &opcodes,
++                             std::vector<JITValue *> &args,
++                             JITStack &stack, JITLocals &locals)
++    {
++      JITCallFasterFunction *r =
++        new JITCallFasterFunction(func, code,
++                                  opcodes, args,
++                                  stack.stack, locals.locals);
++      trace_.push_back(r);
++      return r;
++    }
++
 +    JITOpcodeInfo *createOpcodeInfo(int lasti, JITStack &stack, JITLocals &locals)
 +    {
 +      JITOpcodeInfo *r = new JITOpcodeInfo(lasti, stack.stack, locals.locals);
 +      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);
++      trace_.push_back(r);
++      return r;
++    }
++
 +    JITLoadConst *createLoadConst(int oparg)
 +    {
 +      JITLoadConst *r = new JITLoadConst(oparg);
 +      return r;
 +    }
 +
++    std::vector<JITOpcode *> &trace()
++    {
++      return trace_;
++    }
++
 +  private:
 +    std::vector<JITLocalValue *> loaded_locals_;
 +    std::vector<JITStackValue *> loaded_stack_;
 new file mode 100644
 --- /dev/null
 +++ b/JIT/jit_types.h
-@@ -0,0 +1,280 @@
+@@ -0,0 +1,309 @@
 +// -*- C++ -*-
 +#ifndef PYTHON_JIT_TYPES_H_
 +#define PYTHON_JIT_TYPES_H_
 +    virtual void setGuard(bool v) = 0;
 +    virtual PyTypeObject *getPyType() const = 0;
 +
++    virtual bool hasNullGuard() const = 0;
++    virtual void setNullGuard(bool v) = 0;
 +  };
 +
 +  class JITOpaqueObject : public JITType {
 +  public:
 +    JITOpaqueObject()
-+      : value_(NULL)
++      : value_(NULL), has_null_guard_(NULL)
 +    {
 +    }
 +
 +
 +    virtual bool hasGuard() const
 +    {
-+      return true;
++      return false;
 +    }
 +
 +    virtual void setGuard(bool)
 +      return NULL;
 +    }
 +
++    virtual bool hasNullGuard() const
++    {
++      return has_null_guard_;
++    }
++    virtual void setNullGuard(bool v)
++    {
++      has_null_guard_ = v;
++    }
++
 +  private:
 +    llvm::Value *value_;
++    bool has_null_guard_;
 +  };
 +
 +  class JITBoxedFloat : public JITType {
 +  public:
 +    JITBoxedFloat()
-+      : value_(NULL), naked_value_(NULL), has_guard_(false)
++      : value_(NULL), naked_value_(NULL),
++        has_guard_(false), has_null_guard_(false)
 +    {
 +    }
 +
 +      return &PyFloat_Type;
 +    }
 +
++    virtual bool hasNullGuard() const
++    {
++      return has_null_guard_;
++    }
++    virtual void setNullGuard(bool v)
++    {
++      has_null_guard_ = v;
++    }
++
 +  private:
 +    llvm::Value *value_;
 +    llvm::Value *naked_value_;
 +    bool has_guard_;
++    bool has_null_guard_;
 +  };
 +
 +  class JITNakedFloat : public JITType {
 +    {
 +      if (value_) {
 +        JITFunctionState *state = fbuilder.getState();
-+        // This is always != NULL
 +        state->DecRef(value_);
 +      }
 +      -- increfs_;
 +      return &PyFloat_Type;
 +    }
 +
++    virtual bool hasNullGuard() const
++    {
++      return true;
++    }
++    virtual void setNullGuard(bool v)
++    {}
++
 +  private:
 +    llvm::Value *value_;
 +    llvm::Value *naked_value_;
  	find build -name 'fficonfig.py' -exec rm -f {} ';' || true
 +	rm -f $(BCLIBRARY_OBJS)
 +	rm -f $(BCLIBRARY)
- 	-rm -f Lib/lib2to3/*Grammar*.pickle
+ 	-rm -f $(srcdir)/Lib/lib2to3/*Grammar*.pickle
  	-rm -f $(SYSCONFIGDATA)
  	-rm -f Modules/_testembed Modules/_freeze_importlib
 diff --git a/Modules/_jit.c b/Modules/_jit.c
 new file mode 100644
 --- /dev/null
 +++ b/dotests.py
-@@ -0,0 +1,248 @@
+@@ -0,0 +1,342 @@
 +import unittest
 +import _jit
 +
 +
++def global_add_one_float(v):
++    return v + 1.0
++
++
++def global_add_one_long(v):
++    return v + 1
++
++
++def global_identity(v):
++    return v
++
++
 +class Utilities:
 +    def setUp(self):
 +        self.seq_float = [float(i) for i in range(20)]
 +        self.analyse(doit, self.seq_float)
 +        self.analyse(doit, self.seq_int)
 +
-+    def testCallPythonFunc(self):
++
++class TestFunctionInlining(Utilities, unittest.TestCase):
++    def testCallFasterPythonFunc(self):
 +        def doit(seq):
 +            acc = 0.0
 +            x = lambda v: v
 +        self.analyse(doit, self.seq_float)
 +        self.analyse(doit, self.seq_int)
 +        ftxt = doit.__code__._dump_jit()
++        self.assertTrue("PyObject_Call" not in ftxt)
++
++        def doit(seq):
++            acc = 0.0
++            x = lambda v: v + 1  # TODO + 1.0
++            for i in seq:
++                acc += x(i)
++            return acc
++
++        self.analyse(doit, self.seq_float)
++        self.analyse(doit, self.seq_int)
++        ftxt = doit.__code__._dump_jit()
++        self.assertTrue("PyObject_Call" not in ftxt)
++
++    def testDoubleFasterFunction(self):
++        def func(v):
++            return global_add_one_float(v)
++
++        def doit(seq):
++            acc = 0.0
++            x = func
++            for i in seq:
++                acc += x(i)
++            return acc
++
++        self.analyse(doit, self.seq_float)
++        self.analyse(doit, self.seq_int)
++        ftxt = doit.__code__._dump_jit()
++        self.assertTrue("PyObject_Call" not in ftxt)
++
++    def testCodeBailFasterFunc(self):
++        func1 = lambda x: x / 0.5
++        func2 = lambda x: x / 2.0
++
++        def doit(seq, x):
++            acc = 0.0
++            for i in seq:
++                acc += x(i)
++            return acc
++
++        seq1 = [float(v) for v in range(10)]
++        seq2 = range(10)
++
++        r1_1 = doit(seq1, func1)
++        r2_1 = doit(seq2, func1)
++        r1_2 = doit(seq1, func2)
++        r2_2 = doit(seq2, func2)
++
++        _jit.activate()
++        r1_1_c = doit(seq1, func1)
++        _jit.deactivate()
++        self.assertTrue(doit.__code__._has_jit())
++        ftxt = doit.__code__._dump_jit()
++        self.assertTrue("PyObject_Call" not in ftxt)
++        self.assertTrue("PyNumber" not in ftxt)
++
++        b = doit(seq1, func1)
++        self.assertAlmostEqual(r1_1, b)
++        b = doit(seq2, func1)
++        self.assertAlmostEqual(r2_1, b)
++        b = doit(seq1, func2)
++        self.assertAlmostEqual(r1_2, b)
++        b = doit(seq2, func2)
++        self.assertAlmostEqual(r2_2, b)
++
++    def testCallFasterMethod(self):
++        class foo:
++            def func(self, v):
++                return v + 1.0
++
++        def doit(seq):
++            acc = 0.0
++            x = foo().func
++            for i in seq:
++                acc += x(i)
++            return acc
++
++        self.analyse(doit, self.seq_float)
++        self.analyse(doit, self.seq_int)
++        ftxt = doit.__code__._dump_jit()
 +        self.assertTrue("PyObject_Call" in ftxt)
 +
 +
 diff --git a/setup.py b/setup.py
 --- a/setup.py
 +++ b/setup.py
-@@ -729,6 +729,8 @@
+@@ -750,6 +750,8 @@
          # CSV files
          exts.append( Extension('_csv', ['_csv.c']) )