<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Sun, 19 Jun 2016 at 21:01 Mark Shannon <<a href="mailto:mark@hotpy.org">mark@hotpy.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
On 19/06/16 18:29, Brett Cannon wrote:<br>
><br>
><br>
> On Sat, 18 Jun 2016 at 21:49 Guido van Rossum <<a href="mailto:guido@python.org" target="_blank">guido@python.org</a><br>
> <mailto:<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>>> wrote:<br>
><br>
>     Hi Brett,<br>
><br>
>     I've got a few questions about the specific design. Probably you<br>
>     know the answers, it would be nice to have them in the PEP.<br>
><br>
><br>
> Once you're happy with my answers I'll update the PEP.<br>
><br>
><br>
>     First, why not have a global hook? What does a hook per interpreter<br>
>     give you? Would even finer granularity buy anything?<br>
><br>
><br>
> We initially considered a per-code object hook, but we figured it was<br>
> unnecessary to have that level of control, especially since people like<br>
> Numba have gotten away with not needing it for this long (although I<br>
> suspect that's because they are a decorator so they can just return an<br>
> object that overrides __call__()). We didn't think that a global one was<br>
> appropriate as different workloads may call for different<br>
> JITs/debuggers/etc. and there is no guarantee that you are executing<br>
> every interpreter with the same workload. Plus we figured people might<br>
> simply import their JIT of choice and as a side-effect set the hook, and<br>
> since imports are a per-interpreter thing that seemed to suggest the<br>
> granularity of interpreters.<br>
><br>
> IOW it seemed to be more in line with sys.settrace() than some global<br>
> thing for the process.<br>
><br>
><br>
>     Next, I'm a bit (but no more than a bit) concerned about the extra 8<br>
>     bytes per code object, especially since for most people this is just<br>
>     waste (assuming most people won't be using Pyjion or Numba). Could<br>
>     it be a compile-time feature (requiring recompilation of CPython but<br>
>     not extensions)?<br>
><br>
><br>
> Probably. It does water down potential usage thanks to needing a special<br>
> build. If the decision is "special build or not", I would simply pull<br>
> out this part of the proposal as I wouldn't want to add a flag that<br>
> influences what is or is not possible for an interpreter.<br>
><br>
>     Could you figure out some other way to store per-code-object data?<br>
>     It seems you considered this but decided that the co_extra field was<br>
>     simpler and faster; I'm basically pushing a little harder on this.<br>
>     Of course most of the PEP would disappear without this feature; the<br>
>     extra interpreter field is fine.<br>
><br>
><br>
> Dino and I thought of two potential alternatives, neither of which we<br>
> have taken the time to implement and benchmark. One is to simply have a<br>
> hash table of memory addresses to JIT data that is kept on the JIT side<br>
> of things. Obviously it would be nice to avoid the overhead of a hash<br>
> table lookup on every function call. This also doesn't help minimize<br>
> memory when the code object gets GC'ed.<br>
<br>
Hash lookups aren't that slow.</blockquote><div><br></div><div>There's "slow" and there's "slower".<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> If you combine it with the custom flags<br>
suggested by MRAB, then you would only suffer the lookup penalty when<br>
actually entering the special interpreter.<br></blockquote><div><br></div><div>You actually will always need the lookup in the JIT case to increment the execution count if you're not always immediately JIT-ing. That means MRAB's flag won't necessarily be that useful in the JIT case (it could in the debugging case, though, if you're really aiming for the fastest debugger possible).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
You can use a weakref callback to ensure things get GC'd properly.<br></blockquote><div><br></div><div>Yes, that was already the plan if we lost co_extra.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Also, if there is a special extra field on code-object, then everyone<br>
will want to use it. How do you handle clashes?<br></blockquote><div><br></div><div>As already explained in the PEP in <a href="https://www.python.org/dev/peps/pep-0523/#expanding-pycodeobject">https://www.python.org/dev/peps/pep-0523/#expanding-pycodeobject</a>, like consenting adults. The expectation is that there will not be multiple users of the object at the same time.<br><br></div><div>-Brett<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
><br>
> The other potential solution we came up with was to use weakrefs. I have<br>
> not looked into the details, but we were thinking that if we registered<br>
> the JIT data object as a weakref on the code object, couldn't we iterate<br>
> through the weakrefs attached to the code object to look for the JIT<br>
> data object, and then get the reference that way? It would let us avoid<br>
> a more expensive hash table lookup if we assume most code objects won't<br>
> have a weakref on it (assuming weakrefs are stored in a list), and it<br>
> gives us the proper cleanup semantics we want by getting the weakref<br>
> cleanup callback execution to make sure we decref the JIT data object<br>
> appropriately. But as I said, I have not looked into the feasibility of<br>
> this at all to know if I'm remembering the weakref implementation<br>
> details correctly.<br>
><br>
><br>
>     Finally, there are some error messages from pep2html.py:<br>
>     <a href="https://www.python.org/dev/peps/pep-0523/#copyright" rel="noreferrer" target="_blank">https://www.python.org/dev/peps/pep-0523/#copyright</a><br>
><br>
><br>
> All fixed in<br>
> <a href="https://github.com/python/peps/commit/6929f850a5af07e51d0163558a5fe8d6b85dccfe" rel="noreferrer" target="_blank">https://github.com/python/peps/commit/6929f850a5af07e51d0163558a5fe8d6b85dccfe</a> .<br>
><br>
> -Brett<br>
><br>
><br>
><br>
>     --Guido<br>
><br>
>     On Fri, Jun 17, 2016 at 7:58 PM, Brett Cannon <<a href="mailto:brett@python.org" target="_blank">brett@python.org</a><br>
>     <mailto:<a href="mailto:brett@python.org" target="_blank">brett@python.org</a>>> wrote:<br>
><br>
>         I have taken PEP 523 for this:<br>
>         <a href="https://github.com/python/peps/blob/master/pep-0523.txt" rel="noreferrer" target="_blank">https://github.com/python/peps/blob/master/pep-0523.txt</a> .<br>
><br>
>         I'm waiting until Guido gets back from vacation, at which point<br>
>         I'll ask for a pronouncement or assignment of a BDFL delegate.<br>
><br>
>         On Fri, 3 Jun 2016 at 14:37 Brett Cannon <<a href="mailto:brett@python.org" target="_blank">brett@python.org</a><br>
>         <mailto:<a href="mailto:brett@python.org" target="_blank">brett@python.org</a>>> wrote:<br>
><br>
>             For those of you who follow python-ideas or were at the<br>
>             PyCon US 2016 language summit, you have already seen/heard<br>
>             about this PEP. For those of you who don't fall into either<br>
>             of those categories, this PEP proposed a frame evaluation<br>
>             API for CPython. The motivating example of this work has<br>
>             been Pyjion, the experimental CPython JIT Dino Viehland and<br>
>             I have been working on in our spare time at Microsoft. The<br>
>             API also works for debugging, though, as already<br>
>             demonstrated by Google having added a very similar API<br>
>             internally for debugging purposes.<br>
><br>
>             The PEP is pasted in below and also available in rendered<br>
>             form at<br>
>             <a href="https://github.com/Microsoft/Pyjion/blob/master/pep.rst" rel="noreferrer" target="_blank">https://github.com/Microsoft/Pyjion/blob/master/pep.rst</a> (I<br>
>             will assign myself a PEP # once discussion is finished as<br>
>             it's easier to work in git for this for the rich rendering<br>
>             of the in-progress PEP).<br>
><br>
>             I should mention that the difference from python-ideas and<br>
>             the language summit in the PEP are the listed support from<br>
>             Google's use of a very similar API as well as clarifying the<br>
>             co_extra field on code objects doesn't change their<br>
>             immutability (at least from the view of the PEP).<br>
><br>
>             ----------<br>
>             PEP: NNN<br>
>             Title: Adding a frame evaluation API to CPython<br>
>             Version: $Revision$<br>
>             Last-Modified: $Date$<br>
>             Author: Brett Cannon <<a href="mailto:brett@python.org" target="_blank">brett@python.org</a><br>
>             <mailto:<a href="mailto:brett@python.org" target="_blank">brett@python.org</a>>>,<br>
>                      Dino Viehland <<a href="mailto:dinov@microsoft.com" target="_blank">dinov@microsoft.com</a><br>
>             <mailto:<a href="mailto:dinov@microsoft.com" target="_blank">dinov@microsoft.com</a>>><br>
>             Status: Draft<br>
>             Type: Standards Track<br>
>             Content-Type: text/x-rst<br>
>             Created: 16-May-2016<br>
>             Post-History: 16-May-2016<br>
>                            03-Jun-2016<br>
><br>
><br>
>             Abstract<br>
>             ========<br>
><br>
>             This PEP proposes to expand CPython's C API [#c-api]_ to<br>
>             allow for<br>
>             the specification of a per-interpreter function pointer to<br>
>             handle the<br>
>             evaluation of frames [#pyeval_evalframeex]_. This proposal also<br>
>             suggests adding a new field to code objects [#pycodeobject]_<br>
>             to store<br>
>             arbitrary data for use by the frame evaluation function.<br>
><br>
><br>
>             Rationale<br>
>             =========<br>
><br>
>             One place where flexibility has been lacking in Python is in<br>
>             the direct<br>
>             execution of Python code. While CPython's C API [#c-api]_<br>
>             allows for<br>
>             constructing the data going into a frame object and then<br>
>             evaluating it<br>
>             via ``PyEval_EvalFrameEx()`` [#pyeval_evalframeex]_, control<br>
>             over the<br>
>             execution of Python code comes down to individual objects<br>
>             instead of a<br>
>             hollistic control of execution at the frame level.<br>
><br>
>             While wanting to have influence over frame evaluation may<br>
>             seem a bit<br>
>             too low-level, it does open the possibility for things such as a<br>
>             method-level JIT to be introduced into CPython without<br>
>             CPython itself<br>
>             having to provide one. By allowing external C code to<br>
>             control frame<br>
>             evaluation, a JIT can participate in the execution of Python<br>
>             code at<br>
>             the key point where evaluation occurs. This then allows for<br>
>             a JIT to<br>
>             conditionally recompile Python bytecode to machine code as<br>
>             desired<br>
>             while still allowing for executing regular CPython bytecode when<br>
>             running the JIT is not desired. This can be accomplished by<br>
>             allowing<br>
>             interpreters to specify what function to call to evaluate a<br>
>             frame. And<br>
>             by placing the API at the frame evaluation level it allows for a<br>
>             complete view of the execution environment of the code for<br>
>             the JIT.<br>
><br>
>             This ability to specify a frame evaluation function also<br>
>             allows for<br>
>             other use-cases beyond just opening CPython up to a JIT. For<br>
>             instance,<br>
>             it would not be difficult to implement a tracing or<br>
>             profiling function<br>
>             at the call level with this API. While CPython does provide the<br>
>             ability to set a tracing or profiling function at the Python<br>
>             level,<br>
>             this would be able to match the data collection of the<br>
>             profiler and<br>
>             quite possibly be faster for tracing by simply skipping per-line<br>
>             tracing support.<br>
><br>
>             It also opens up the possibility of debugging where the frame<br>
>             evaluation function only performs special debugging work when it<br>
>             detects it is about to execute a specific code object. In that<br>
>             instance the bytecode could be theoretically rewritten<br>
>             in-place to<br>
>             inject a breakpoint function call at the proper point for<br>
>             help in<br>
>             debugging while not having to do a heavy-handed approach as<br>
>             required by ``sys.settrace()``.<br>
><br>
>             To help facilitate these use-cases, we are also proposing<br>
>             the adding<br>
>             of a "scratch space" on code objects via a new field. This<br>
>             will allow<br>
>             per-code object data to be stored with the code object<br>
>             itself for easy<br>
>             retrieval by the frame evaluation function as necessary. The<br>
>             field<br>
>             itself will simply be a ``PyObject *`` type so that any data<br>
>             stored in<br>
>             the field will participate in normal object memory management.<br>
><br>
><br>
>             Proposal<br>
>             ========<br>
><br>
>             All proposed C API changes below will not be part of the<br>
>             stable ABI.<br>
><br>
><br>
>             Expanding ``PyCodeObject``<br>
>             --------------------------<br>
><br>
>             One field is to be added to the ``PyCodeObject`` struct<br>
>             [#pycodeobject]_::<br>
><br>
>                typedef struct {<br>
>                   ...<br>
>                   PyObject *co_extra;  /* "Scratch space" for the code<br>
>             object. */<br>
>                } PyCodeObject;<br>
><br>
>             The ``co_extra`` will be ``NULL`` by default and will not be<br>
>             used by<br>
>             CPython itself. Third-party code is free to use the field as<br>
>             desired.<br>
>             Values stored in the field are expected to not be required<br>
>             in order<br>
>             for the code object to function, allowing the loss of the<br>
>             data of the<br>
>             field to be acceptable (this keeps the code object as<br>
>             immutable from<br>
>             a functionality point-of-view; this is slightly contentious<br>
>             and so is<br>
>             listed as an open issue in `Is co_extra needed?`_). The<br>
>             field will be<br>
>             freed like all other fields on ``PyCodeObject`` during<br>
>             deallocation<br>
>             using ``Py_XDECREF()``.<br>
><br>
>             It is not recommended that multiple users attempt to use the<br>
>             ``co_extra`` simultaneously. While a dictionary could<br>
>             theoretically be<br>
>             set to the field and various users could use a key specific<br>
>             to the<br>
>             project, there is still the issue of key collisions as well as<br>
>             performance degradation from using a dictionary lookup on<br>
>             every frame<br>
>             evaluation. Users are expected to do a type check to make<br>
>             sure that<br>
>             the field has not been previously set by someone else.<br>
><br>
><br>
>             Expanding ``PyInterpreterState``<br>
>             --------------------------------<br>
><br>
>             The entrypoint for the frame evalution function is<br>
>             per-interpreter::<br>
><br>
>                // Same type signature as PyEval_EvalFrameEx().<br>
>                typedef PyObject* (__stdcall<br>
>             *PyFrameEvalFunction)(PyFrameObject*, int);<br>
><br>
>                typedef struct {<br>
>                    ...<br>
>                    PyFrameEvalFunction eval_frame;<br>
>                } PyInterpreterState;<br>
><br>
>             By default, the ``eval_frame`` field will be initialized to<br>
>             a function<br>
>             pointer that represents what ``PyEval_EvalFrameEx()``<br>
>             currently is<br>
>             (called ``PyEval_EvalFrameDefault()``, discussed later in<br>
>             this PEP).<br>
>             Third-party code may then set their own frame evaluation<br>
>             function<br>
>             instead to control the execution of Python code. A pointer<br>
>             comparison<br>
>             can be used to detect if the field is set to<br>
>             ``PyEval_EvalFrameDefault()`` and thus has not been mutated yet.<br>
><br>
><br>
>             Changes to ``Python/ceval.c``<br>
>             -----------------------------<br>
><br>
>             ``PyEval_EvalFrameEx()`` [#pyeval_evalframeex]_ as it<br>
>             currently stands<br>
>             will be renamed to ``PyEval_EvalFrameDefault()``. The new<br>
>             ``PyEval_EvalFrameEx()`` will then become::<br>
><br>
>                  PyObject *<br>
>                  PyEval_EvalFrameEx(PyFrameObject *frame, int throwflag)<br>
>                  {<br>
>                      PyThreadState *tstate = PyThreadState_GET();<br>
>                      return tstate->interp->eval_frame(frame, throwflag);<br>
>                  }<br>
><br>
>             This allows third-party code to place themselves directly in<br>
>             the path<br>
>             of Python code execution while being backwards-compatible<br>
>             with code<br>
>             already using the pre-existing C API.<br>
><br>
><br>
>             Updating ``python-gdb.py``<br>
>             --------------------------<br>
><br>
>             The generated ``python-gdb.py`` file used for Python support<br>
>             in GDB<br>
>             makes some hard-coded assumptions about<br>
>             ``PyEval_EvalFrameEx()``, e.g.<br>
>             the names of local variables. It will need to be updated to<br>
>             work with<br>
>             the proposed changes.<br>
><br>
><br>
>             Performance impact<br>
>             ==================<br>
><br>
>             As this PEP is proposing an API to add pluggability, performance<br>
>             impact is considered only in the case where no third-party<br>
>             code has<br>
>             made any changes.<br>
><br>
>             Several runs of pybench [#pybench]_ consistently showed no<br>
>             performance<br>
>             cost from the API change alone.<br>
><br>
>             A run of the Python benchmark suite [#py-benchmarks]_ showed no<br>
>             measurable cost in performance.<br>
><br>
>             In terms of memory impact, since there are typically not<br>
>             many CPython<br>
>             interpreters executing in a single process that means the<br>
>             impact of<br>
>             ``co_extra`` being added to ``PyCodeObject`` is the only worry.<br>
>             According to [#code-object-count]_, a run of the Python test<br>
>             suite<br>
>             results in about 72,395 code objects being created. On a 64-bit<br>
>             CPU that would result in 579,160 bytes of extra memory being<br>
>             used if<br>
>             all code objects were alive at once and had nothing set in their<br>
>             ``co_extra`` fields.<br>
><br>
><br>
>             Example Usage<br>
>             =============<br>
><br>
>             A JIT for CPython<br>
>             -----------------<br>
><br>
>             Pyjion<br>
>             ''''''<br>
><br>
>             The Pyjion project [#pyjion]_ has used this proposed API to<br>
>             implement<br>
>             a JIT for CPython using the CoreCLR's JIT [#coreclr]_. Each code<br>
>             object has its ``co_extra`` field set to a<br>
>             ``PyjionJittedCode`` object<br>
>             which stores four pieces of information:<br>
><br>
>             1. Execution count<br>
>             2. A boolean representing whether a previous attempt to JIT<br>
>             failed<br>
>             3. A function pointer to a trampoline (which can be type<br>
>             tracing or not)<br>
>             4. A void pointer to any JIT-compiled machine code<br>
><br>
>             The frame evaluation function has (roughly) the following<br>
>             algorithm::<br>
><br>
>                  def eval_frame(frame, throw_flag):<br>
>                      pyjion_code = frame.code.co_extra<br>
>                      if not pyjion_code:<br>
>                          frame.code.co_extra = PyjionJittedCode()<br>
>                      elif not pyjion_code.jit_failed:<br>
>                          if not pyjion_code.jit_code:<br>
>                              return<br>
>             pyjion_code.eval(pyjion_code.jit_code, frame)<br>
>                          elif pyjion_code.exec_count > 20_000:<br>
>                              if jit_compile(frame):<br>
>                                  return<br>
>             pyjion_code.eval(pyjion_code.jit_code, frame)<br>
>                              else:<br>
>                                  pyjion_code.jit_failed = True<br>
>                      pyjion_code.exec_count += 1<br>
>                      return PyEval_EvalFrameDefault(frame, throw_flag)<br>
><br>
>             The key point, though, is that all of this work and logic is<br>
>             separate<br>
>             from CPython and yet with the proposed API changes it is able to<br>
>             provide a JIT that is compliant with Python semantics (as of<br>
>             this<br>
>             writing, performance is almost equivalent to CPython without<br>
>             the new<br>
>             API). This means there's nothing technically preventing<br>
>             others from<br>
>             implementing their own JITs for CPython by utilizing the<br>
>             proposed API.<br>
><br>
><br>
>             Other JITs<br>
>             ''''''''''<br>
><br>
>             It should be mentioned that the Pyston team was consulted on an<br>
>             earlier version of this PEP that was more JIT-specific and<br>
>             they were<br>
>             not interested in utilizing the changes proposed because<br>
>             they want<br>
>             control over memory layout they had no interest in directly<br>
>             supporting<br>
>             CPython itself. An informal discusion with a developer on<br>
>             the PyPy<br>
>             team led to a similar comment.<br>
><br>
>             Numba [#numba]_, on the other hand, suggested that they would be<br>
>             interested in the proposed change in a post-1.0 future for<br>
>             themselves [#numba-interest]_.<br>
><br>
>             The experimental Coconut JIT [#coconut]_ could have<br>
>             benefitted from<br>
>             this PEP. In private conversations with Coconut's creator we<br>
>             were told<br>
>             that our API was probably superior to the one they developed for<br>
>             Coconut to add JIT support to CPython.<br>
><br>
><br>
>             Debugging<br>
>             ---------<br>
><br>
>             In conversations with the Python Tools for Visual Studio<br>
>             team (PTVS)<br>
>             [#ptvs]_, they thought they would find these API changes<br>
>             useful for<br>
>             implementing more performant debugging. As mentioned in the<br>
>             Rationale_<br>
>             section, this API would allow for switching on debugging<br>
>             functionality<br>
>             only in frames where it is needed. This could allow for either<br>
>             skipping information that ``sys.settrace()`` normally<br>
>             provides and<br>
>             even go as far as to dynamically rewrite bytecode prior to<br>
>             execution<br>
>             to inject e.g. breakpoints in the bytecode.<br>
><br>
>             It also turns out that Google has provided a very similar API<br>
>             internally for years. It has been used for performant debugging<br>
>             purposes.<br>
><br>
><br>
>             Implementation<br>
>             ==============<br>
><br>
>             A set of patches implementing the proposed API is available<br>
>             through<br>
>             the Pyjion project [#pyjion]_. In its current form it has more<br>
>             changes to CPython than just this proposed API, but that is<br>
>             for ease<br>
>             of development instead of strict requirements to accomplish<br>
>             its goals.<br>
><br>
><br>
>             Open Issues<br>
>             ===========<br>
><br>
>             Allow ``eval_frame`` to be ``NULL``<br>
>             -----------------------------------<br>
><br>
>             Currently the frame evaluation function is expected to<br>
>             always be set.<br>
>             It could very easily simply default to ``NULL`` instead<br>
>             which would<br>
>             signal to use ``PyEval_EvalFrameDefault()``. The current<br>
>             proposal of<br>
>             not special-casing the field seemed the most<br>
>             straight-forward, but it<br>
>             does require that the field not accidentally be cleared,<br>
>             else a crash<br>
>             may occur.<br>
><br>
><br>
>             Is co_extra needed?<br>
>             -------------------<br>
><br>
>             While discussing this PEP at PyCon US 2016, some core developers<br>
>             expressed their worry of the ``co_extra`` field making code<br>
>             objects<br>
>             mutable. The thinking seemed to be that having a field that was<br>
>             mutated after the creation of the code object made the<br>
>             object seem<br>
>             mutable, even though no other aspect of code objects changed.<br>
><br>
>             The view of this PEP is that the `co_extra` field doesn't<br>
>             change the<br>
>             fact that code objects are immutable. The field is specified<br>
>             in this<br>
>             PEP as to not contain information required to make the code<br>
>             object<br>
>             usable, making it more of a caching field. It could be viewed as<br>
>             similar to the UTF-8 cache that string objects have internally;<br>
>             strings are still considered immutable even though they have<br>
>             a field<br>
>             that is conditionally set.<br>
><br>
>             The field is also not strictly necessary. While the field<br>
>             greatly<br>
>             simplifies attaching extra information to code objects,<br>
>             other options<br>
>             such as keeping a mapping of code object memory addresses to<br>
>             what<br>
>             would have been kept in ``co_extra`` or perhaps using a weak<br>
>             reference<br>
>             of the data on the code object and then iterating through<br>
>             the weak<br>
>             references until the attached data is found is possible. But<br>
>             obviously<br>
>             all of these solutions are not as simple or performant as<br>
>             adding the<br>
>             ``co_extra`` field.<br>
><br>
><br>
>             Rejected Ideas<br>
>             ==============<br>
><br>
>             A JIT-specific C API<br>
>             --------------------<br>
><br>
>             Originally this PEP was going to propose a much larger API<br>
>             change<br>
>             which was more JIT-specific. After soliciting feedback from<br>
>             the Numba<br>
>             team [#numba]_, though, it became clear that the API was<br>
>             unnecessarily<br>
>             large. The realization was made that all that was truly<br>
>             needed was the<br>
>             opportunity to provide a trampoline function to handle<br>
>             execution of<br>
>             Python code that had been JIT-compiled and a way to attach that<br>
>             compiled machine code along with other critical data to the<br>
>             corresponding Python code object. Once it was shown that<br>
>             there was no<br>
>             loss in functionality or in performance while minimizing the API<br>
>             changes required, the proposal was changed to its current form.<br>
><br>
><br>
>             References<br>
>             ==========<br>
><br>
>             .. [#pyjion] Pyjion project<br>
>                 (<a href="https://github.com/microsoft/pyjion" rel="noreferrer" target="_blank">https://github.com/microsoft/pyjion</a>)<br>
><br>
>             .. [#c-api] CPython's C API<br>
>                 (<a href="https://docs.python.org/3/c-api/index.html" rel="noreferrer" target="_blank">https://docs.python.org/3/c-api/index.html</a>)<br>
><br>
>             .. [#pycodeobject] ``PyCodeObject``<br>
>                 (<a href="https://docs.python.org/3/c-api/code.html#c.PyCodeObject" rel="noreferrer" target="_blank">https://docs.python.org/3/c-api/code.html#c.PyCodeObject</a>)<br>
><br>
>             .. [#coreclr] .NET Core Runtime (CoreCLR)<br>
>                 (<a href="https://github.com/dotnet/coreclr" rel="noreferrer" target="_blank">https://github.com/dotnet/coreclr</a>)<br>
><br>
>             .. [#pyeval_evalframeex] ``PyEval_EvalFrameEx()``<br>
><br>
>               (<a href="https://docs.python.org/3/c-api/veryhigh.html?highlight=pyframeobject#c.PyEval_EvalFrameEx" rel="noreferrer" target="_blank">https://docs.python.org/3/c-api/veryhigh.html?highlight=pyframeobject#c.PyEval_EvalFrameEx</a>)<br>
><br>
>             .. [#pycodeobject] ``PyCodeObject``<br>
>                 (<a href="https://docs.python.org/3/c-api/code.html#c.PyCodeObject" rel="noreferrer" target="_blank">https://docs.python.org/3/c-api/code.html#c.PyCodeObject</a>)<br>
><br>
>             .. [#numba] Numba<br>
>                 (<a href="http://numba.pydata.org/" rel="noreferrer" target="_blank">http://numba.pydata.org/</a>)<br>
><br>
>             .. [#numba-interest]  numba-users mailing list:<br>
>                 "Would the C API for a JIT entrypoint being proposed by<br>
>             Pyjion help out Numba?"<br>
><br>
>               (<a href="https://groups.google.com/a/continuum.io/forum/#!topic/numba-users/yRl_0t8-m1g" rel="noreferrer" target="_blank">https://groups.google.com/a/continuum.io/forum/#!topic/numba-users/yRl_0t8-m1g</a>)<br>
><br>
>             .. [#code-object-count] [Python-Dev] Opcode cache in ceval loop<br>
><br>
>               (<a href="https://mail.python.org/pipermail/python-dev/2016-February/143025.html" rel="noreferrer" target="_blank">https://mail.python.org/pipermail/python-dev/2016-February/143025.html</a>)<br>
><br>
>             .. [#py-benchmarks] Python benchmark suite<br>
>                 (<a href="https://hg.python.org/benchmarks" rel="noreferrer" target="_blank">https://hg.python.org/benchmarks</a>)<br>
><br>
>             .. [#pyston] Pyston<br>
>                 (<a href="http://pyston.org" rel="noreferrer" target="_blank">http://pyston.org</a>)<br>
><br>
>             .. [#pypy] PyPy<br>
>                 (<a href="http://pypy.org/" rel="noreferrer" target="_blank">http://pypy.org/</a>)<br>
><br>
>             .. [#ptvs] Python Tools for Visual Studio<br>
>                 (<a href="http://microsoft.github.io/PTVS/" rel="noreferrer" target="_blank">http://microsoft.github.io/PTVS/</a>)<br>
><br>
>             .. [#coconut] Coconut<br>
>                 (<a href="https://github.com/davidmalcolm/coconut" rel="noreferrer" target="_blank">https://github.com/davidmalcolm/coconut</a>)<br>
><br>
><br>
>             Copyright<br>
>             =========<br>
><br>
>             This document has been placed in the public domain.<br>
><br>
><br>
><br>
>             ..<br>
>                 Local Variables:<br>
>                 mode: indented-text<br>
>                 indent-tabs-mode: nil<br>
>                 sentence-end-double-space: t<br>
>                 fill-column: 70<br>
>                 coding: utf-8<br>
>                 End:<br>
><br>
><br>
>         _______________________________________________<br>
>         Python-Dev mailing list<br>
>         <a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a> <mailto:<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a>><br>
>         <a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
>         Unsubscribe:<br>
>         <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
><br>
><br>
><br>
><br>
>     --<br>
>     --Guido van Rossum (<a href="http://python.org/~guido" rel="noreferrer" target="_blank">python.org/~guido</a> <<a href="http://python.org/~guido" rel="noreferrer" target="_blank">http://python.org/~guido</a>>)<br>
><br>
><br>
><br>
> _______________________________________________<br>
> Python-Dev mailing list<br>
> <a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
> Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/mark%40hotpy.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/mark%40hotpy.org</a><br>
><br>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/brett%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/brett%40python.org</a><br>
</blockquote></div></div>