Skip to content
Snippets Groups Projects
  1. Dec 28, 2017
    • Damien George's avatar
      py/nlr: Factor out common NLR code to macro and generic funcs in nlr.c. · b25f9216
      Damien George authored
      Each NLR implementation (Thumb, x86, x64, xtensa, setjmp) duplicates a lot
      of the NLR code, specifically that dealing with pushing and popping the NLR
      pointer to maintain the linked-list of NLR buffers.  This patch factors all
      of that code out of the specific implementations into generic functions in
      nlr.c, along with a helper macro in nlr.h.  This eliminates duplicated
      code.
      b25f9216
    • Damien George's avatar
      py/nlr: Clean up selection and config of NLR implementation. · 5bf8e85f
      Damien George authored
      If MICROPY_NLR_SETJMP is not enabled and the machine is auto-detected then
      nlr.h now defines some convenience macros for the individual NLR
      implementations to use (eg MICROPY_NLR_THUMB).  This keeps nlr.h and the
      implementation in sync, and also makes the nlr_buf_t struct easier to read.
      5bf8e85f
  2. Dec 26, 2017
    • Paul Sokolovsky's avatar
      Revert "py/nlr: Factor out common NLR code to generic functions." · 096e967a
      Paul Sokolovsky authored
      This reverts commit 6a3a742a.
      
      The above commit has number of faults starting from the motivation down
      to the actual implementation.
      
      1. Faulty implementation.
      
      The original code contained functions like:
      
      NORETURN void nlr_jump(void *val) {
          nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
          nlr_buf_t *top = *top_ptr;
      ...
           __asm volatile (
          "mov    %0, %%edx           \n" // %edx points to nlr_buf
          "mov    28(%%edx), %%esi    \n" // load saved %esi
          "mov    24(%%edx), %%edi    \n" // load saved %edi
          "mov    20(%%edx), %%ebx    \n" // load saved %ebx
          "mov    16(%%edx), %%esp    \n" // load saved %esp
          "mov    12(%%edx), %%ebp    \n" // load saved %ebp
          "mov    8(%%edx), %%eax     \n" // load saved %eip
          "mov    %%eax, (%%esp)      \n" // store saved %eip to stack
          "xor    %%eax, %%eax        \n" // clear return register
          "inc    %%al                \n" // increase to make 1, non-local return
           "ret                        \n" // return
          :                               // output operands
          : "r"(top)                      // input operands
          :                               // clobbered registers
           );
      }
      
      Which clearly stated that C-level variable should be a parameter of the
      assembly, whcih then moved it into correct register.
      
      Whereas now it's:
      
      NORETURN void nlr_jump_tail(nlr_buf_t *top) {
          (void)top;
      
          __asm volatile (
          "mov    28(%edx), %esi      \n" // load saved %esi
          "mov    24(%edx), %edi      \n" // load saved %edi
          "mov    20(%edx), %ebx      \n" // load saved %ebx
          "mov    16(%edx), %esp      \n" // load saved %esp
          "mov    12(%edx), %ebp      \n" // load saved %ebp
          "mov    8(%edx), %eax       \n" // load saved %eip
          "mov    %eax, (%esp)        \n" // store saved %eip to stack
          "xor    %eax, %eax          \n" // clear return register
          "inc    %al                 \n" // increase to make 1, non-local return
          "ret                        \n" // return
          );
      
          for (;;); // needed to silence compiler warning
      }
      
      Which just tries to perform operations on a completely random register (edx
      in this case). The outcome is the expected: saving the pure random luck of
      the compiler putting the right value in the random register above, there's
      a crash.
      
      2. Non-critical assessment.
      
      The original commit message says "There is a small overhead introduced
      (typically 1 machine instruction)". That machine instruction is a call
      if a compiler doesn't perform tail optimization (happens regularly), and
      it's 1 instruction only with the broken code shown above, fixing it
      requires adding more. With inefficiencies already presented in the NLR
      code, the overhead becomes "considerable" (several times more than 1%),
      not "small".
      
      The commit message also says "This eliminates duplicated code.". An
      obvious way to eliminate duplication would be to factor out common code
      to macros, not introduce overhead and breakage like above.
      
      3. Faulty motivation.
      
      All this started with a report of warnings/errors happening for a niche
      compiler. It could have been solved in one the direct ways: a) fixing it
      just for affected compiler(s); b) rewriting it in proper assembly (like
      it was before BTW); c) by not doing anything at all, MICROPY_NLR_SETJMP
      exists exactly to address minor-impact cases like thar (where a) or b) are
      not applicable). Instead, a backwards "solution" was put forward, leading
      to all the issues above.
      
      The best action thus appears to be revert and rework, not trying to work
      around what went haywire in the first place.
      096e967a
  3. Dec 20, 2017
    • Damien George's avatar
      py/nlr: Factor out common NLR code to generic functions. · 6a3a742a
      Damien George authored
      Each NLR implementation (Thumb, x86, x64, xtensa, setjmp) duplicates a lot
      of the NLR code, specifically that dealing with pushing and popping the NLR
      pointer to maintain the linked-list of NLR buffers.  This patch factors all
      of that code out of the specific implementations into generic functions in
      nlr.c.  This eliminates duplicated code.
      
      The factoring also allows to make the machine-specific NLR code pure
      assembler code, thus allowing nlrthumb.c to use naked function attributes
      in the correct way (naked functions can only have basic inline assembler
      code in them).
      
      There is a small overhead introduced (typically 1 machine instruction)
      because now the generic nlr_jump() must call nlr_jump_tail() rather than
      them being one combined function.
      6a3a742a
  4. Dec 11, 2017
    • Damien George's avatar
      py: Introduce a Python stack for scoped allocation. · 02d830c0
      Damien George authored
      This patch introduces the MICROPY_ENABLE_PYSTACK option (disabled by
      default) which enables a "Python stack" that allows to allocate and free
      memory in a scoped, or Last-In-First-Out (LIFO) way, similar to alloca().
      
      A new memory allocation API is introduced along with this Py-stack.  It
      includes both "local" and "nonlocal" LIFO allocation.  Local allocation is
      intended to be equivalent to using alloca(), whereby the same function must
      free the memory.  Nonlocal allocation is where another function may free
      the memory, so long as it's still LIFO.
      
      Follow-up patches will convert all uses of alloca() and VLA to the new
      scoped allocation API.  The old behaviour (using alloca()) will still be
      available, but when MICROPY_ENABLE_PYSTACK is enabled then alloca() is no
      longer required or used.
      
      The benefits of enabling this option are (or will be once subsequent
      patches are made to convert alloca()/VLA):
      - Toolchains without alloca() can use this feature to obtain correct and
        efficient scoped memory allocation (compared to using the heap instead
        of alloca(), which is slower).
      - Even if alloca() is available, enabling the Py-stack gives slightly more
        efficient use of stack space when calling nested Python functions, due to
        the way that compilers implement alloca().
      - Enabling the Py-stack with the stackless mode allows for even more
        efficient stack usage, as well as retaining high performance (because the
        heap is no longer used to build and destroy stackless code states).
      - With Py-stack and stackless enabled, Python-calling-Python is no longer
        recursive in the C mp_execute_bytecode function.
      
      The micropython.pystack_use() function is included to measure usage of the
      Python stack.
      02d830c0
  5. Oct 04, 2017
    • Damien George's avatar
      all: Remove inclusion of internal py header files. · a3dc1b19
      Damien George authored
      Header files that are considered internal to the py core and should not
      normally be included directly are:
          py/nlr.h - internal nlr configuration and declarations
          py/bc0.h - contains bytecode macro definitions
          py/runtime0.h - contains basic runtime enums
      
      Instead, the top-level header files to include are one of:
          py/obj.h - includes runtime0.h and defines everything to use the
              mp_obj_t type
          py/runtime.h - includes mpstate.h and hence nlr.h, obj.h, runtime0.h,
              and defines everything to use the general runtime support functions
      
      Additional, specific headers (eg py/objlist.h) can be included if needed.
      a3dc1b19
  6. Mar 06, 2017
Loading