changeset 32150:994b527e0ffe

update to VM patch from June 7 2023 JWE note: When I first applied the VM changes I accidentally used the original patch posted to https://savannah.gnu.org/patch/?10344 instead of the one posted to comment #3. This changeset updates Octave with the additional diffs present in the later patch file except for the object pool classes that we will consider separately. I'm not including any additional comments here because if these changes had been part of the original series of commits (as I intended) then they would have all been part of changes that had "new file" or "new class" ChangeLog entries. Changed files: compile.cc, stack-frame.cc, ov-fcn.cc, ov-fcn.h, ov-vm.h, pt-bytecode-vm-internal.h, pt-bytecode-vm.cc, pt-bytecode-vm.h, pt-bytecode-walk.cc, pt-bytecode-walk.h, pt-bytecode.h, bench.m, bench.py, module.mk, bytecode.tst,bytecode_eval_1.m, bytecode_leaks.m, bytecode_misc.m, bytecode_return.m, bytecode_subfuncs.m, bytecode_varargout.m.
author Petter T. <petter.vilhelm@gmail.com>
date Mon, 19 Jun 2023 20:07:05 -0400
parents 6e6e99e8a4de
children 72dcb1cef2c9
files libinterp/corefcn/compile.cc libinterp/corefcn/stack-frame.cc libinterp/octave-value/ov-fcn.cc libinterp/octave-value/ov-fcn.h libinterp/octave-value/ov-vm.h libinterp/parse-tree/pt-bytecode-vm-internal.h libinterp/parse-tree/pt-bytecode-vm.cc libinterp/parse-tree/pt-bytecode-vm.h libinterp/parse-tree/pt-bytecode-walk.cc libinterp/parse-tree/pt-bytecode-walk.h libinterp/parse-tree/pt-bytecode.h test/compile-bench/bench-octave/bench.m test/compile-bench/bench-py3/bench.py test/compile-bench/module.mk test/compile/bytecode.tst test/compile/bytecode_eval_1.m test/compile/bytecode_leaks.m test/compile/bytecode_misc.m test/compile/bytecode_return.m test/compile/bytecode_subfuncs.m test/compile/bytecode_varargout.m
diffstat 21 files changed, 1892 insertions(+), 881 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/compile.cc	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/corefcn/compile.cc	Mon Jun 19 20:07:05 2023 -0400
@@ -89,6 +89,26 @@
   return octave_value {true};
 }
 
+DEFUN (__vm_print_trace, , ,
+  doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{prints_trace} =} __vm_print_trace ())
+
+Internal function.
+
+Print a debug trace from the VM. Toggles on or off each call.
+
+There has to be a breakpoint set in some file for the trace
+to actually print anything.
+
+Returns true if a trace will be printed from now on, false otherwise.
+
+@end deftypefn */)
+{
+  vm::m_trace_enabled = !vm::m_trace_enabled;
+
+  return octave_value {vm::m_trace_enabled};
+}
+
 DEFUN (__ref_count, args, ,
   doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{count} =} __ref_count (@var{obj}))
@@ -109,6 +129,23 @@
   return octave_value {ov.get_count ()};
 }
 
+DEFMETHOD (__vm_is_executing, interp, , ,
+  doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{is_executing} =} __vm_is_executing ())
+
+Internal function.
+
+Returns true if the VM is executing the function calling __vm_is_executing ().
+
+False otherwise.
+
+@end deftypefn */)
+{
+  bool bytecode_running = interp.get_evaluator ().get_current_stack_frame ()->is_bytecode_fcn_frame ();
+
+  return octave_value {bytecode_running};
+}
+
 DEFMETHOD (__vm_profile, interp, args, ,
   doc: /* -*- texinfo -*-
 @deftypefn  {} {} __vm_profile on
@@ -141,6 +178,11 @@
 Toggles between profiling and printing the result of the profiler.
 Clears the profiler on each print.
 
+@item info
+Prints the profiler data.
+
+Not that output to a variable is not implemented yet.
+
 @end table
 
 @end deftypefn */)
@@ -218,7 +260,7 @@
 
 DEFMETHOD (__print_bytecode, interp, args, ,
   doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{count} =} __rep_count (@var{fn_name}))
+@deftypefn  {} {@var{success} =} __print_bytecode (@var{fn_name}))
 
 Internal function.
 
@@ -265,9 +307,9 @@
 
 DEFMETHOD (__compile, interp, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{success} =} compile (@var{fn_name})
-@deftypefnx  {} {@var{success} =} compile (@var{fn_name}, "clear")
-@deftypefnx  {} {@var{success} =} compile (@var{fn_name}, "print")
+@deftypefn  {} {@var{success} =} __compile (@var{fn_name})
+@deftypefnx  {} {@var{success} =} __compile (@var{fn_name}, "clear")
+@deftypefnx  {} {@var{success} =} __compile (@var{fn_name}, "print")
 
 Compile the specified function to bytecode.
 
@@ -367,7 +409,8 @@
 }
 
 // If TRUE, use VM evaluator rather than tree walker.
-
+// FIXME: Use OCTAVE_ENABLE_VM_EVALUATOR define to set it to true when
+// the VM has been tested properly.
 bool V__enable_vm_eval__ = false;
 
 DEFUN (__enable_vm_eval__, args, nargout,
@@ -380,8 +423,10 @@
 
 Note that the virtual machine feature is experimental.
 
-The default value is set when building Octave by the OCTAVE_ENABLE_VM_EVALUATOR
-flag.
+The default value is currently false, while the VM is still experimental.
+Users need to explicitly call @code{__enable_vm_eval__ (1)} to enable it.
+In future, this will be set to the value of  the OCTAVE_ENABLE_VM_EVALUATOR
+flag that was set when building Octave.
 
 When false, Octave uses a traditional tree walker
 to evaluate statements parsed from m-code.  When true, Octave translates parsed
--- a/libinterp/corefcn/stack-frame.cc	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/corefcn/stack-frame.cc	Mon Jun 19 20:07:05 2023 -0400
@@ -91,7 +91,7 @@
       m_name_data (vm.m_name_data),
       m_stack_start (vm.m_sp),
       m_code (vm.m_code),
-      m_size (vm.m_name_data_size),
+      m_size (m_unwind_data->m_ids_size),
       // The above fields in vm change during execution so we need to store them in the frame
       m_vm (&vm),
       m_nargin (nargin),
@@ -123,6 +123,7 @@
     m_orig_size = elt.m_orig_size;
     m_ip = elt.m_ip;
     m_unwind_data = elt.m_unwind_data; // TODO: Ownership?
+    m_size = m_unwind_data->m_ids_size;
 
     if (elt.m_lazy_data)
       {
@@ -140,22 +141,20 @@
   bytecode_fcn_stack_frame&
   operator = (bytecode_fcn_stack_frame&& elt)
   {
-    if (m_stack_cpy)
-      {
-        // Note: int nargout at offset 0
-        for (unsigned i = 1; i < m_size; i++)
-          m_stack_cpy[i].ov.~octave_value ();
-        delete m_stack_cpy;
-      }
-
     if (m_lazy_data)
       {
+        if (m_lazy_data->m_stack_cpy)
+          {
+            // Note: int nargout at offset 0
+            for (unsigned i = 1; i < m_size; i++)
+              m_lazy_data->m_stack_cpy[i].ov.~octave_value ();
+            delete m_lazy_data->m_stack_cpy;
+          }
         delete m_lazy_data->m_unwind_protect_frame;
         delete m_lazy_data;
       }
 
     *this = std::move (elt);
-    elt.m_stack_cpy = nullptr;
     elt.m_lazy_data = nullptr;
 
     return *this;
@@ -165,18 +164,18 @@
   // so they both call dispose()
   void dispose ()
   {
-     if (m_stack_cpy)
-      {
-        // Note: int nargout at offset 0
-        for (unsigned i = 1; i < m_size; i++)
-          m_stack_cpy[i].ov.~octave_value ();
-        delete m_stack_cpy;
-      }
-
     if (m_lazy_data)
       {
+        if (m_lazy_data->m_stack_cpy)
+          {
+            // Note: int nargout at offset 0
+            for (unsigned i = 1; i < m_size; i++)
+              m_lazy_data->m_stack_cpy[i].ov.~octave_value ();
+            delete m_lazy_data->m_stack_cpy;
+          }
         delete m_lazy_data->m_unwind_protect_frame;
         delete m_lazy_data;
+        m_lazy_data = nullptr;
       }   
   }
 
@@ -294,6 +293,14 @@
       {
         delete m_lazy_data->m_unwind_protect_frame;
         m_lazy_data->m_unwind_protect_frame = nullptr;
+
+        // Restore warningstates
+        if (m_fcn)
+          {
+            auto usr_fn_p = m_fcn->user_function_value ();
+            if (usr_fn_p)
+              usr_fn_p->restore_warning_states (); // TODO: octave_user_function::restore_warning_states() could be static.
+          }
       }
 
     if (is_alone)
@@ -320,16 +327,18 @@
     // Copy the stack to the frame
     size_t stack_slots = m_size;
 
-    m_stack_cpy = new octave::stack_element[stack_slots];
+    lazy_data ();
+
+    m_lazy_data->m_stack_cpy = new octave::stack_element[stack_slots];
     for (unsigned i = 1; i < m_size; i++)
-      new (&m_stack_cpy[i].ov) octave_value {};
+      new (&m_lazy_data->m_stack_cpy[i].ov) octave_value {};
 
     // Note: int nargout at offset 0
-    m_stack_cpy[0].i = m_stack_start[0].i;
+    m_lazy_data->m_stack_cpy[0].i = m_stack_start[0].i;
     for (unsigned i = 1; i < m_size; i++)
-      m_stack_cpy[i].ov = m_stack_start[i].ov;
-
-    m_stack_start = m_stack_cpy;
+      m_lazy_data->m_stack_cpy[i].ov = m_stack_start[i].ov;
+
+    m_stack_start = m_lazy_data->m_stack_cpy;
   }
 
   std::size_t size (void) const
@@ -893,6 +902,7 @@
     std::vector<scope_flags> m_extra_flags;
 
     unwind_protect *m_unwind_protect_frame = nullptr;
+    stack_element *m_stack_cpy = nullptr;
   };
 
   lazy_data_struct & lazy_data ()
@@ -910,10 +920,10 @@
 
   std::string *m_name_data;
   stack_element *m_stack_start;
-  stack_element *m_stack_cpy = nullptr;
+
   unsigned char *m_code;
-  std::size_t m_size;
-  std::size_t m_orig_size;
+  unsigned m_size;
+  unsigned m_orig_size;
   vm *m_vm;
   int m_ip;
 
--- a/libinterp/octave-value/ov-fcn.cc	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/octave-value/ov-fcn.cc	Mon Jun 19 20:07:05 2023 -0400
@@ -97,6 +97,9 @@
 {
   clear_cached_function ();
 
+  if (!ov.is_defined ())
+    return;
+
   // We need to keep a reference to the metaobject for as long as the function is alive
   if (ov.is_classdef_meta ())
     m_cached_object = ov;
@@ -162,44 +165,47 @@
 
 octave_function *
 octave_fcn_cache::
-get_cached_fcn (const octave_value_list& args)
+get_cached_fcn_internal (const octave_value_list& args)
 {
+  clear_cached_function ();
+
   octave_function *fcn = nullptr;
-
   octave_idx_type current_n_updated = octave::load_path::get_weak_n_updated ();
-  if (has_cached_function (args))
-    {
-      if (m_n_updated == current_n_updated)
-        return m_cached_function.function_value (true);
-      else
-        clear_cached_function ();
-    }
+
+  octave::interpreter& interp =
+    octave::__get_interpreter__ ();
 
-  if (! fcn)
+  octave::symbol_table& symtab = interp.get_symbol_table ();
+  octave_value val = symtab.find_function (m_fcn_name, args);
+
+  if (val.is_function ())
     {
-      octave::interpreter& interp =
-        octave::__get_interpreter__ ();
-
-      octave::symbol_table& symtab = interp.get_symbol_table ();
-      octave_value val = symtab.find_function (m_fcn_name, args);
-
-      if (val.is_function ())
-        {
-          fcn = val.function_value (true);
-          set_cached_function (val, args, current_n_updated);
-          return fcn;
-        }
-      
-      val = symtab.find_function (m_fcn_name);
-      if (val.is_function ())
-        {
-          return val.function_value (true);
-        }
+      fcn = val.function_value (true);
+      set_cached_function (val, args, current_n_updated);
+      return fcn;
+    }
+  
+  val = symtab.find_function (m_fcn_name);
+  if (val.is_function ())
+    {
+      return val.function_value (true);
     }
 
   return fcn;
 }
 
+octave_function *
+octave_fcn_cache::
+get_cached_fcn (const octave_value_list& args)
+{
+  octave_idx_type current_n_updated = octave::load_path::get_weak_n_updated ();
+  if (OCTAVE_LIKELY (has_cached_function (args)))
+    if (OCTAVE_LIKELY (m_n_updated == current_n_updated))
+      return m_cached_function.function_value (true);
+
+  return get_cached_fcn_internal (args);
+}
+
 octave_value_list
 octave_fcn_cache::
 call (octave::tree_evaluator& tw,
--- a/libinterp/octave-value/ov-fcn.h	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/octave-value/ov-fcn.h	Mon Jun 19 20:07:05 2023 -0400
@@ -86,22 +86,28 @@
 
   bool has_cached_function (const octave_value_list &args) const
   {
-    auto vec_n = static_cast <octave_idx_type> (m_cached_args.size ());
-
-    if (args.length () != vec_n)
+    if (m_n_updated == 0)
       return false;
 
-    for (int i = 0; i < args.length (); i++)
+    unsigned vec_n = m_cached_args.size ();
+
+    unsigned n_args = args.length ();
+    if (n_args != vec_n)
+      return false;
+
+    for (unsigned i = 0; i < n_args; i++)
       {
         if (args (i).type_id () != m_cached_args [i])
           return false;
       }
 
-    return m_cached_function.is_defined ();
+    return true;
   }
 
 private:
 
+  octave_function * get_cached_fcn_internal (const octave_value_list& args);
+
   void clear_cached_function ()
   {
     m_cached_object = octave_value {};
@@ -110,8 +116,6 @@
     m_cached_args.clear ();
   }
 
-  //std::weak_ptr<int> get_lp_n_updated () const { return m_n_updated; }
-
   octave_value m_cached_object;
   octave_value m_cached_function;
   std::vector<int> m_cached_args;
--- a/libinterp/octave-value/ov-vm.h	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/octave-value/ov-vm.h	Mon Jun 19 20:07:05 2023 -0400
@@ -29,6 +29,7 @@
 #include "octave-config.h"
 
 #include "ov.h"
+#include "load-path.h"
 
 
 // octave_value_vm is to be used only by the VM
@@ -165,4 +166,38 @@
   octave_base_value *m_rep;
 };
 
+class
+octave_cached_value : public octave_base_value
+{
+public:
+
+  octave_cached_value ()
+  {
+    m_n_updated = octave::load_path::get_weak_n_updated ();
+  }
+
+  void set_cached_obj (octave_value cache_obj)
+  {
+    m_cached_object = cache_obj;
+  }
+
+  octave_value get_cached_value ()
+  {
+    return m_cached_object;
+  }
+
+  bool cache_is_valid ()
+  {
+    return m_n_updated == octave::load_path::get_weak_n_updated () && m_cached_object.is_defined ();
+  }
+
+  bool is_defined () const { return true; }
+
+
+private:
+
+  octave_value m_cached_object;
+  octave_idx_type m_n_updated = 0;
+};
+
 #endif
--- a/libinterp/parse-tree/pt-bytecode-vm-internal.h	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-vm-internal.h	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 2001-2022 The Octave Project Developers
+// Copyright (C) 2022-2023 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -89,6 +89,7 @@
       STACK_DESTROY (2);                \
       PUSH_OV (std::move (ans));        \
     }                                   \
+  CATCH_INTERRUPT_EXCEPTION             \
   CATCH_INDEX_EXCEPTION                 \
   CATCH_EXECUTION_EXCEPTION             \
   CATCH_BAD_ALLOC                       \
@@ -104,7 +105,7 @@
   int t_type = target_type;                                                              \
   if (OCTAVE_UNLIKELY (rhs_type != lhs_type || rhs_type != t_type))                      \
     {                                                                                    \
-      ip[-1] = static_cast<unsigned char> (INSTR::op_target);                            \
+      ip[-2] = static_cast<unsigned char> (INSTR::op_target);                            \
       goto jmp_target;                                                                   \
     }                                                                                    \
                                                                                          \
@@ -114,6 +115,7 @@
       rhs.~octave_value ();                                                              \
       STACK_SHRINK (1);                                                                  \
     }                                                                                    \
+  CATCH_INTERRUPT_EXCEPTION                                                              \
   CATCH_INDEX_EXCEPTION                                                                  \
   CATCH_EXECUTION_EXCEPTION                                                              \
   CATCH_BAD_ALLOC                                                                        \
@@ -126,7 +128,7 @@
   if (OCTAVE_UNLIKELY (ov.type_id () != target_type))                                    \
     {                                                                                    \
       /* Change the specialized opcode to the generic one */                             \
-      ip[-1] = static_cast<unsigned char> (INSTR::op_target);                            \
+      ip[-2] = static_cast<unsigned char> (INSTR::op_target);                            \
       goto jmp_target;                                                                   \
     }                                                                                    \
                                                                                          \
@@ -134,6 +136,7 @@
     {                                                                                    \
       ov = op_fn (ov.get_rep ());                                          \
     }                                                                                    \
+  CATCH_INTERRUPT_EXCEPTION                                                              \
   CATCH_INDEX_EXCEPTION                                                                  \
   CATCH_EXECUTION_EXCEPTION                                                              \
   CATCH_BAD_ALLOC                                                                        \
@@ -148,7 +151,7 @@
   int lhs_type = lhs.type_id ();                                                           \
   if (rhs_type == lhs_type && rhs_type == m_scalar_typeid)                                 \
     {                                                                                      \
-      ip[-1] = static_cast<unsigned char> (INSTR::op_target);                              \
+      ip[-2] = static_cast<unsigned char> (INSTR::op_target);                              \
       goto jmp_target;                                                                     \
     }                                                                                      \
                                                                                            \
@@ -161,6 +164,7 @@
       STACK_DESTROY (2);                                                                   \
       PUSH_OV (std::move (ans));                                                           \
     }                                                                                      \
+  CATCH_INTERRUPT_EXCEPTION                                                                \
   CATCH_INDEX_EXCEPTION                                                                    \
   CATCH_EXECUTION_EXCEPTION                                                                \
   CATCH_BAD_ALLOC                                                                          \
@@ -193,7 +197,13 @@
   goto unwind;                                           \
 }                                                        \
 
-
+#define CATCH_INTERRUPT_EXCEPTION \
+catch (interrupt_exception& e)                                          \
+  {                                                                     \
+    (*sp++).i = static_cast<int>(error_type::INTERRUPT_EXC);            \
+    goto unwind;                                                        \
+  }                                                                     \
+ 
 #define CATCH_EXECUTION_EXCEPTION \
 catch (execution_exception& e)                                          \
   {                                                                     \
@@ -204,6 +214,35 @@
     goto unwind;                                                        \
   }                                                                     \
 
+#define CATCH_STACKPUSH_EXECUTION_EXCEPTION \
+catch (execution_exception& e)                                          \
+  {                                                                     \
+    m_could_not_push_frame = true;                                      \
+    (*sp++).pee = new execution_exception {e};                          \
+    (*sp++).i = static_cast<int> (error_type::EXECUTION_EXC);           \
+                                                                        \
+    goto unwind;                                                        \
+  }                                                                     \
+
+#define CATCH_STACKPUSH_BAD_ALLOC \
+catch (const std::bad_alloc&)                                           \
+{                                                                       \
+  m_could_not_push_frame = true;                                        \
+  (*sp++).i = static_cast<int> (error_type::BAD_ALLOC);                 \
+                                                                        \
+  goto unwind;                                                          \
+}
+
+#define CATCH_EXIT_EXCEPTION \
+catch (const exit_exception& e)                                         \
+{                                                                       \
+  (*sp++).i = e.exit_status ();                                         \
+  (*sp++).i = e.safe_to_return ();                                      \
+  (*sp++).i = static_cast<int> (error_type::EXIT_EXCEPTION);            \
+                                                                        \
+  goto unwind;                                                          \
+}
+
 #define CATCH_BAD_ALLOC \
 catch (const std::bad_alloc&)                                           \
 {                                                                       \
@@ -213,11 +252,16 @@
 }
 
 #define MAKE_BYTECODE_CALL \
-CHECK_STACK_N (stack_min_for_new_call);                                                           \
+if (sp + stack_min_for_new_call >= m_stack + stack_size)                                          \
+  {                                                                                               \
+    (*sp++).pee = new execution_exception {"error","","VM is running out of stack space"};        \
+    (*sp++).i = static_cast<int> (error_type::EXECUTION_EXC);                                     \
+    goto unwind;                                                                                  \
+  }                                                                                               \
 /* We are now going to call another function */                                                   \
 /* compiled to bytecode */                                                                        \
                                                                                                   \
-m_tw->set_active_bytecode_ip (ip - code);                                                                \
+m_tw->set_active_bytecode_ip (ip - code);                                                         \
 stack_element *first_arg = sp - n_args_on_stack;                                                  \
                                                                                                   \
 /* Push address to first arg (or would one would have been */                                     \
@@ -263,7 +307,6 @@
 m_data = data = bc.m_data.data ();                                                                \
 m_code = code = bc.m_code.data ();                                                                \
 m_name_data = name_data = bc.m_ids.data ();                                                       \
-m_name_data_size = bc.m_ids.size ();                                                              \
 m_unwind_data = unwind_data = &bc.m_unwind_data;                                                  \
                                                                                                   \
                                                                                                   \
@@ -272,7 +315,7 @@
 int n_returns_callee = static_cast<signed char> (*ip++); /* Negative for varargout */             \
 n_returns_callee = n_returns_callee >= 0 ? n_returns_callee : -n_returns_callee;                  \
 int n_args_callee = static_cast<signed char> (*ip++); /* Negative for varargin */                 \
-int n_locals_callee = *ip++;                                                                      \
+int n_locals_callee = POP_CODE_USHORT ();                                                         \
                                                                                                   \
 if (n_args_callee < 0)                                                                            \
 {                                                                                                 \
@@ -333,7 +376,14 @@
 for (int i = 0; i < n_locals_to_ctor; i++)                                                        \
   PUSH_OV ();                                                                                     \
                                                                                                   \
-m_tw->push_stack_frame(*this, usr_fcn, nargout, n_args_on_callee_stack);                          \
+                                                                                                  \
+try                                                                                               \
+  {                                                                                               \
+    m_tw->push_stack_frame(*this, usr_fcn, nargout, n_args_on_callee_stack);                      \
+  }                                                                                               \
+CATCH_STACKPUSH_EXECUTION_EXCEPTION /* Sets m_could_not_push_frame to true */                     \
+CATCH_STACKPUSH_BAD_ALLOC                                                                         \
+                                                                                                  \
 /* "auto var" in the frame object. This is needed if nargout() etc are called */                  \
 set_nargout (nargout);                                                                            \
 /* Called fn needs to know about ignored outputs .e.g. [~, a] = foo() */                          \
--- a/libinterp/parse-tree/pt-bytecode-vm.cc	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-vm.cc	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 1996-2022 The Octave Project Developers
+// Copyright (C) 2022-2023 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -55,6 +55,7 @@
 static bool ov_need_stepwise_subsrefs (octave_value &ov);
 static void copy_many_args_to_caller (octave::stack_element *sp, octave::stack_element *caller_stack_end,
                                       int n_args_to_move, int n_args_caller_expects);
+static int lhs_assign_numel (octave_value &ov, const std::string& type, const std::list<octave_value_list>& idx);
 
 #define TODO(msg) error("Not done yet %d: " msg, __LINE__)
 #define ERR(msg) error("VM error %d: " msg, __LINE__)
@@ -91,9 +92,10 @@
   unsigned char *p = v_code.data ();
   unsigned char *code = p;
   int n = v_code.size ();
+  bool wide_opext_active = false;
 
   // Skip some framedata
-  p += 3;
+  p += 4;
 
   std::vector<std::pair<int, std::string>> v_pair_row_str;
 
@@ -141,14 +143,34 @@
     unsigned u = b0 | (b1 << 8);    \
     s += " " + std::to_string (u);}
 
-#define PSLOT() \
-    {p++;                                                               \
-    CHECK_END ();                                                       \
-    s += " " + std::to_string (*p);                                     \
+#define PSSLOT() \
+    {p++;                                                            \
+    CHECK_END ();                                                    \
+    s += " " + std::to_string (*p);                                  \
     v_ids.push_back (std::string {*p < names.size() ?                \
                                       names[*p].c_str() :            \
                                       "INVALID SLOT"});}
 
+#define PSLOT() \
+    {if (wide_opext_active)                                         \
+      PWSLOT ()                                                     \
+    else                                                            \
+      PSSLOT ()                                                     \
+    wide_opext_active = false;}
+
+#define PWSLOT() \
+    {p++;                                                           \
+    CHECK_END ();                                                   \
+    unsigned char b0 = *p;                                          \
+    p++;                                                            \
+    CHECK_END ();                                                   \
+    unsigned char b1 = *p;                                          \
+    unsigned u = b0 | (b1 << 8);                                    \
+    s += " " + std::to_string (u);                                  \
+    v_ids.push_back (std::string {u < names.size() ?                \
+                                      names[u].c_str() :            \
+                                      "INVALID SLOT"});}
+
 #define CHECK_END() \
   do {if (p >= v_code.data () + v_code.size ()) { error ("Invalid bytecode\n");}} while((0))
 
@@ -164,13 +186,14 @@
     u |= *p++ << 16;\
     CHECK_END ();\
     u |= *p << 24;\
-    s += std::to_string (u) + " ";\
+    s += " " + std::to_string (u);\
   } while (0);
 
   while (p < code + n)
     {
       switch (static_cast<INSTR> (*p))
         {
+
           PRINT_OP (POP)
           PRINT_OP (DUP)
           PRINT_OP (MUL)
@@ -238,6 +261,13 @@
           PRINT_OP (PUSH_DBL_1);
           PRINT_OP (PUSH_DBL_2);
 
+          CASE_START (WIDE)
+            wide_opext_active = true;
+          CASE_END ()
+
+          CASE_START (PUSH_FOLDED_CST) PSLOT () PSHORT () CASE_END ()
+          CASE_START (SET_FOLDED_CST) PSLOT () CASE_END ()
+
           CASE_START (LOAD_CST)       PCHAR () CASE_END ()
           CASE_START (LOAD_CST_ALT2)  PCHAR () CASE_END ()
           CASE_START (LOAD_CST_ALT3)  PCHAR () CASE_END ()
@@ -264,8 +294,8 @@
           CASE_START (PUSH_SLOT_NARGOUT0)         PSLOT() CASE_END ()
           CASE_START (SET_SLOT_TO_STACK_DEPTH)    PSLOT() CASE_END ()
 
-          CASE_START (DISP)           PSLOT() PSLOT() CASE_END ()
-          CASE_START (PUSH_SLOT_DISP) PSLOT() PSLOT() CASE_END ()
+          CASE_START (DISP)           PSLOT() PWSLOT() CASE_END ()
+          CASE_START (PUSH_SLOT_DISP) PSLOT() PWSLOT() CASE_END ()
 
           CASE_START (JMP_IFDEF)                PSHORT() CASE_END ()
           CASE_START (JMP_IFNCASEMATCH)         PSHORT() CASE_END ()
@@ -278,39 +308,39 @@
 
           CASE_START (ASSIGN_COMPOUND)        PSLOT () PCHAR () CASE_END ()
 
-          CASE_START (INDEX_ID_NARGOUT0)      PCHAR () PSLOT () CASE_END ()
-          CASE_START (INDEX_ID_NARGOUT1)      PCHAR () PSLOT () CASE_END ()
-          CASE_START (INDEX_ID1_MAT_2D)       PCHAR () PSLOT () CASE_END ()
-          CASE_START (INDEX_ID1_MAT_1D)       PCHAR () PSLOT () CASE_END ()
-
-          CASE_START (INDEX_CELL_ID_NARGOUT0) PCHAR () PSLOT () CASE_END ()
-          CASE_START (INDEX_CELL_ID_NARGOUT1) PCHAR () PSLOT () CASE_END ()
-
-          CASE_START (INDEX_CELL_ID_NARGOUTN) PCHAR () PCHAR () PSLOT () CASE_END ()
-          CASE_START (INDEX_IDN)              PCHAR () PCHAR () PSLOT () CASE_END ()
+          CASE_START (INDEX_ID_NARGOUT0)      PSLOT () PCHAR () CASE_END ()
+          CASE_START (INDEX_ID_NARGOUT1)      PSLOT () PCHAR () CASE_END ()
+          CASE_START (INDEX_ID1_MAT_2D)       PSLOT () PCHAR () CASE_END ()
+          CASE_START (INDEX_ID1_MAT_1D)       PSLOT () PCHAR () CASE_END ()
+
+          CASE_START (INDEX_CELL_ID_NARGOUT0) PSLOT () PCHAR () CASE_END ()
+          CASE_START (INDEX_CELL_ID_NARGOUT1) PSLOT () PCHAR () CASE_END ()
+
+          CASE_START (INDEX_CELL_ID_NARGOUTN) PSLOT () PCHAR () PCHAR () CASE_END ()
+          CASE_START (INDEX_IDN)              PSLOT () PCHAR () PCHAR () CASE_END ()
 
           CASE_START (SUBASSIGN_OBJ)          PCHAR () PCHAR () CASE_END ()
           CASE_START (MATRIX)                 PCHAR () PCHAR () CASE_END ()
           CASE_START (DUPN)                   PCHAR () PCHAR () CASE_END ()
 
-          CASE_START (INDEX_ID1_MATHY_UFUN)   PCHAR () PCHAR () PSLOT () CASE_END ()
-
-          CASE_START (INDEX_OBJ)              PCHAR () PCHAR () PCHAR () PCHAR () PCHAR () CASE_END ()
-
-          CASE_START (FOR_COND) PSHORT () PSLOT () CASE_END ()
-
-          CASE_START (FOR_COMPLEX_COND) PSHORT () PSLOT () PSLOT () CASE_END ()
-
-          CASE_START (INDEX_STRUCT_NARGOUTN)  PCHAR () PCHAR () PSLOT () CASE_END ()
-          CASE_START (END_ID)                 PCHAR () PCHAR () PSLOT () CASE_END ()
+          CASE_START (INDEX_ID1_MATHY_UFUN)   PCHAR () PSLOT () PCHAR () CASE_END ()
+
+          CASE_START (INDEX_OBJ)              PCHAR () PCHAR () PWSLOT () PCHAR () PCHAR () CASE_END ()
+
+          CASE_START (FOR_COND) PSLOT () PSHORT () CASE_END ()
+
+          CASE_START (FOR_COMPLEX_COND) PSHORT () PWSLOT () PWSLOT () CASE_END ()
+
+          CASE_START (INDEX_STRUCT_NARGOUTN)  PCHAR () PWSLOT () PWSLOT () CASE_END ()
+          CASE_START (END_ID)                 PSLOT () PCHAR () PCHAR () CASE_END ()
 
           CASE_START (PUSH_SLOT_NARGOUTN)     PSLOT () PCHAR () CASE_END ()
           CASE_START (BRAINDEAD_WARNING)      PSLOT () PCHAR () CASE_END ()
-          CASE_START (SUBASSIGN_STRUCT)       PSLOT () PCHAR () CASE_END ()
-
-          CASE_START (SUBASSIGN_ID)         PCHAR () PSLOT () CASE_END ()
-          CASE_START (SUBASSIGN_ID_MAT_1D)  PCHAR () PSLOT () CASE_END ()
-          CASE_START (SUBASSIGN_CELL_ID)    PCHAR () PSLOT () CASE_END ()
+          CASE_START (SUBASSIGN_STRUCT)       PSLOT () PWSLOT () CASE_END ()
+
+          CASE_START (SUBASSIGN_ID)         PSLOT () PCHAR () CASE_END ()
+          CASE_START (SUBASSIGN_ID_MAT_1D)  PSLOT () PCHAR () CASE_END ()
+          CASE_START (SUBASSIGN_CELL_ID)    PSLOT () PCHAR () CASE_END ()
 
           CASE_START (EVAL) PCHAR () PINT () CASE_END ()
 
@@ -335,9 +365,9 @@
 
           CASE_START (LOAD_FAR_CST) PINT () CASE_END ()
 
-          CASE_START (END_OBJ) PCHAR () PCHAR () PSLOT () CASE_END ()
-
-          CASE_START (WORDCMD) PCHAR () PCHAR () PSLOT () CASE_END ()
+          CASE_START (END_OBJ) PSLOT () PCHAR () PCHAR () CASE_END ()
+
+          CASE_START (WORDCMD) PSLOT () PCHAR () PCHAR () CASE_END ()
 
           CASE_START (SET_IGNORE_OUTPUTS)
             PCHAR ()
@@ -352,7 +382,7 @@
             int nn = *p;
             for (int i = 0; i < nn; i++)
               {
-                PSLOT ()
+                PWSLOT ()
               }
           CASE_END ()
 
@@ -365,7 +395,7 @@
                 PCHAR ()
                 PCHAR ()
                 PCHAR ()
-                PSLOT ()
+                PWSLOT ()
               }
           CASE_END ()
 
@@ -376,16 +406,16 @@
 
             if (type == 1)
               {
-                s += "ROWS "; PINT ();
-                s += "COLS "; PINT ();
+                s += " ROWS"; PINT ();
+                s += " COLS"; PINT ();
               }
             else
               {
                 if (p + 3 >= code + n)
                   error ("Invalid bytecode\n");
                 int i = chars_to_uint (p);
-                s += "ROWS "; PINT ();
-                s += "COLS ";
+                s += " ROWS"; PINT ();
+                s += " COLS";
                 for (int j = 0; j < i; j++)
                   PINT ();
               }
@@ -410,8 +440,8 @@
               else if (static_cast<global_type> (*p) == global_type::PERSISTENT)
                 s += " 'PERSISTENT'";
 
-              PSLOT ()
-              PSLOT ()
+              PWSLOT ()
+              PWSLOT ()
 
               s += " HAS-TARGET";
               PCHAR ()
@@ -427,7 +457,7 @@
             PCHAR ()
             int n_slots = *p;
             for (int i = 0; i < n_slots; i++)
-              PSLOT ()
+              PWSLOT ()
           CASE_END ()
 
           default:
@@ -494,12 +524,26 @@
 
   return ans;
 }
+
+static int pop_code_ushort (unsigned char *ip)
+{
+  unsigned int ans;
+  ip -= 2;
+  ans = *ip++;
+  ans |= *ip++ << 8;
+
+  return ans;
+}
+
+
+
 // Debug functions easy to break out into in gdb. Called by __dummy_mark_1() in Octave
 extern "C" void dummy_mark_1 (void);
 extern "C" void dummy_mark_2 (void);
 
 #define POP_CODE() *ip++
 #define POP_CODE_INT() (ip++,ip++,ip++,ip++,pop_code_int (ip))
+#define POP_CODE_USHORT() (ip++, ip++, pop_code_ushort (ip))
 
 #define PUSH_OV(ov) \
   do {                           \
@@ -599,18 +643,31 @@
 \
   if (OCTAVE_UNLIKELY (m_tw->debug_mode ())) /* Do we need to check for breakpoints? */\
     goto debug_check;\
-  goto *instr [*ip++]; /* Dispatch to next instruction */\
+  int opcode = ip[0];\
+  arg0 = ip[1];\
+  ip += 2;\
+  goto *instr [opcode]; /* Dispatch to next instruction */\
 } while ((0))
 
-#define DISPATCH_NO_DEBUG() do { \
+#define DISPATCH_1BYTEOP() do { \
+  /*if (!m_tw->get_current_stack_frame ()->is_bytecode_fcn_frame ()) \
+    { \
+      printf ("Why oh why\n"); \
+      dummy_mark_1 (); \
+    } */ \
   /* PRINT_VM_STATE ("%d" COMMA __LINE__); */ \
-  /*CHECK_STACK (0);*/ \
+  /* CHECK_STACK (0); */ \
 \
-  goto *instr [*ip++]; /* Dispatch to next instruction */\
+  if (OCTAVE_UNLIKELY (m_tw->debug_mode ())) /* Do we need to check for breakpoints? */\
+    goto debug_check_1b;\
+  int opcode = arg0;\
+  arg0 = *ip++;\
+  goto *instr [opcode]; /* Dispatch to next instruction */\
 } while ((0))
 
 std::shared_ptr<vm_profiler> vm::m_vm_profiler;
 bool vm::m_profiler_enabled;
+bool vm::m_trace_enabled;
 
 // These two are used for pushing true and false ov:s to the
 // operand stack.
@@ -640,144 +697,147 @@
   // the array. "&&" is label address, not rvalue reference.
   static const void* instr[] =
     {
-      &&pop,
-      &&dup,
-      &&load_cst,
-      &&mul,
-      &&div,
-      &&add,
-      &&sub,
-      &&ret,
-      &&assign,
-      &&jmp_if,
-      &&jmp,
-      &&jmp_ifn,
-      &&push_slot_nargout0,
-      &&le,
-      &&le_eq,
-      &&gr,
-      &&gr_eq,
-      &&eq,
-      &&neq,
-      &&index_id_nargout0,
-      &&push_slot_indexed,
-      &&pow,
-      &&ldiv,
-      &&el_mul,
-      &&el_div,
-      &&el_pow,
-      &&el_and,
-      &&el_or,
-      &&el_ldiv,
-      &&op_not,
-      &&uadd,
-      &&usub,
-      &&trans,
-      &&herm,
-      &&incr_id_prefix,
-      &&decr_id_prefix,
-      &&incr_id_postfix,
-      &&decr_id_postfix,
-      &&for_setup,
-      &&for_cond,
-      &&pop_n_ints,
-      &&push_slot_nargout1,
-      &&index_id1, // INDEX_ID_NARGOUT1
-      &&push_fcn_handle,
-      &&colon,
-      &&colon,
-      &&colon_cmd,
-      &&colon_cmd,
-      &&push_true,
-      &&push_false,
-      &&unary_true,
-      &&index_idn,
-      &&assign_n,
-      &&push_slot_nargoutn,
-      &&subassign_id,
-      &&end_id,
-      &&matrix,
-      &&trans_mul,
-      &&mul_trans,
-      &&herm_mul,
-      &&mul_herm,
-      &&trans_ldiv,
-      &&herm_ldiv,
-      &&wordcmd,
-      &&handle_signals,
-      &&push_cell,
-      &&push_ov_u64,
-      &&expand_cs_list,
-      &&index_cell_id0,
-      &&index_cell_id1,
-      &&index_cell_idn,
-      &&incr_prefix,
-      &&rot,
-      &&init_global,
-      &&assign_compound,
-      &&jmp_ifdef,
-      &&switch_cmp,
-      &&braindead_precond,
-      &&braindead_warning,
-      &&force_assign,
-      &&push_nil,
-      &&throw_iferrorobj,
-      &&index_struct_n,
-      &&subasgn_struct,
-      &&subasgn_cell_id,
-      &&index_obj,
-      &&subassign_obj,
-      &&matrix_big,
-      &&load_far_cst,
-      &&end_obj,
-      &&set_ignore_outputs,
-      &&clear_ignore_outputs,
-      &&subassign_chained,
-      &&set_slot_to_stack_depth,
-      &&dupn,
-      &&debug,
-      &&index_struct_call,
-      &&end_x_n,
-      &&eval,
-      &&bind_ans,
-      &&push_anon_fcn_handle,
-      &&for_complex_setup,
-      &&for_complex_cond,
-      &&push_slot1_special,
-      &&disp,
-      &&push_slot_disp,
-      &&load_cst_alt2,
-      &&load_cst_alt3,
-      &&load_cst_alt4,
-      &&load_2_cst,
-      &&mul_dbl,
-      &&add_dbl,
-      &&sub_dbl,
-      &&div_dbl,
-      &&pow_dbl,
-      &&le_dbl,
-      &&le_eq_dbl,
-      &&gr_dbl,
-      &&gr_eq_dbl,
-      &&eq_dbl,
-      &&neq_dbl,
-      &&index_id1_mat_1d,
-      &&index_id1_mat_2d,
-      &&push_pi,
-      &&index_math_ufun_id1,
-      &&subassign_id_mat_1d,
-      &&incr_id_prefix_dbl,
-      &&decr_id_prefix_dbl,
-      &&incr_id_postfix_dbl,
-      &&decr_id_postfix_dbl,
-      &&push_cst_dbl_0,
-      &&push_cst_dbl_1,
-      &&push_cst_dbl_2,
-      &&jmp_if_bool,
-      &&jmp_ifn_bool,
-      &&usub_dbl,
-      &&not_dbl,
-      &&not_bool,
+      &&pop,                                               // POP,
+      &&dup,                                               // DUP,
+      &&load_cst,                                          // LOAD_CST,
+      &&mul,                                               // MUL,
+      &&div,                                               // DIV,
+      &&add,                                               // ADD,
+      &&sub,                                               // SUB,
+      &&ret,                                               // RET,
+      &&assign,                                            // ASSIGN,
+      &&jmp_if,                                            // JMP_IF,
+      &&jmp,                                               // JMP,
+      &&jmp_ifn,                                           // JMP_IFN,
+      &&push_slot_nargout0,                                // PUSH_SLOT_NARGOUT0,
+      &&le,                                                // LE,
+      &&le_eq,                                             // LE_EQ,
+      &&gr,                                                // GR,
+      &&gr_eq,                                             // GR_EQ,
+      &&eq,                                                // EQ,
+      &&neq,                                               // NEQ,
+      &&index_id_nargout0,                                 // INDEX_ID_NARGOUT0,
+      &&push_slot_indexed,                                 // PUSH_SLOT_INDEXED,
+      &&pow,                                               // POW,
+      &&ldiv,                                              // LDIV,
+      &&el_mul,                                            // EL_MUL,
+      &&el_div,                                            // EL_DIV,
+      &&el_pow,                                            // EL_POW,
+      &&el_and,                                            // EL_AND,
+      &&el_or,                                             // EL_OR,
+      &&el_ldiv,                                           // EL_LDIV,
+      &&op_not,                                            // NOT,
+      &&uadd,                                              // UADD,
+      &&usub,                                              // USUB,
+      &&trans,                                             // TRANS,
+      &&herm,                                              // HERM,
+      &&incr_id_prefix,                                    // INCR_ID_PREFIX,
+      &&decr_id_prefix,                                    // DECR_ID_PREFIX,
+      &&incr_id_postfix,                                   // INCR_ID_POSTFIX,
+      &&decr_id_postfix,                                   // DECR_ID_POSTFIX,
+      &&for_setup,                                         // FOR_SETUP,
+      &&for_cond,                                          // FOR_COND,
+      &&pop_n_ints,                                        // POP_N_INTS,
+      &&push_slot_nargout1,                                // PUSH_SLOT_NARGOUT1,
+      &&index_id1,                                         // INDEX_ID_NARGOUT1,
+      &&push_fcn_handle,                                   // PUSH_FCN_HANDLE,
+      &&colon,                                             // COLON3,
+      &&colon,                                             // COLON2,
+      &&colon_cmd,                                         // COLON3_CMD,
+      &&colon_cmd,                                         // COLON2_CMD,
+      &&push_true,                                         // PUSH_TRUE,
+      &&push_false,                                        // PUSH_FALSE,
+      &&unary_true,                                        // UNARY_TRUE,
+      &&index_idn,                                         // INDEX_IDN,
+      &&assign_n,                                          // ASSIGNN,
+      &&push_slot_nargoutn,                                // PUSH_SLOT_NARGOUTN,
+      &&subassign_id,                                      // SUBASSIGN_ID,
+      &&end_id,                                            // END_ID,
+      &&matrix,                                            // MATRIX,
+      &&trans_mul,                                         // TRANS_MUL,
+      &&mul_trans,                                         // MUL_TRANS,
+      &&herm_mul,                                          // HERM_MUL,
+      &&mul_herm,                                          // MUL_HERM,
+      &&trans_ldiv,                                        // TRANS_LDIV,
+      &&herm_ldiv,                                         // HERM_LDIV,
+      &&wordcmd,                                           // WORDCMD,
+      &&handle_signals,                                    // HANDLE_SIGNALS,
+      &&push_cell,                                         // PUSH_CELL,
+      &&push_ov_u64,                                       // PUSH_OV_U64,
+      &&expand_cs_list,                                    // EXPAND_CS_LIST,
+      &&index_cell_id0,                                    // INDEX_CELL_ID_NARGOUT0,
+      &&index_cell_id1,                                    // INDEX_CELL_ID_NARGOUT1,
+      &&index_cell_idn,                                    // INDEX_CELL_ID_NARGOUTN,
+      &&incr_prefix,                                       // INCR_PREFIX,
+      &&rot,                                               // ROT,
+      &&init_global,                                       // GLOBAL_INIT,
+      &&assign_compound,                                   // ASSIGN_COMPOUND,
+      &&jmp_ifdef,                                         // JMP_IFDEF,
+      &&switch_cmp,                                        // JMP_IFNCASEMATCH,
+      &&braindead_precond,                                 // BRAINDEAD_PRECONDITION,
+      &&braindead_warning,                                 // BRAINDEAD_WARNING,
+      &&force_assign,                                      // FORCE_ASSIGN, // Accepts undefined rhs
+      &&push_nil,                                          // PUSH_NIL,
+      &&throw_iferrorobj,                                  // THROW_IFERROBJ,
+      &&index_struct_n,                                    // INDEX_STRUCT_NARGOUTN,
+      &&subasgn_struct,                                    // SUBASSIGN_STRUCT,
+      &&subasgn_cell_id,                                   // SUBASSIGN_CELL_ID,
+      &&index_obj,                                         // INDEX_OBJ,
+      &&subassign_obj,                                     // SUBASSIGN_OBJ,
+      &&matrix_big,                                        // MATRIX_UNEVEN,
+      &&load_far_cst,                                      // LOAD_FAR_CST,
+      &&end_obj,                                           // END_OBJ,
+      &&set_ignore_outputs,                                // SET_IGNORE_OUTPUTS,
+      &&clear_ignore_outputs,                              // CLEAR_IGNORE_OUTPUTS,
+      &&subassign_chained,                                 // SUBASSIGN_CHAINED,
+      &&set_slot_to_stack_depth,                           // SET_SLOT_TO_STACK_DEPTH,
+      &&dupn,                                              // DUPN,
+      &&debug,                                             // DEBUG,
+      &&index_struct_call,                                 // INDEX_STRUCT_CALL,
+      &&end_x_n,                                           // END_X_N,
+      &&eval,                                              // EVAL,
+      &&bind_ans,                                          // BIND_ANS,
+      &&push_anon_fcn_handle,                              // PUSH_ANON_FCN_HANDLE,
+      &&for_complex_setup,                                 // FOR_COMPLEX_SETUP, // opcode
+      &&for_complex_cond,                                  // FOR_COMPLEX_COND,
+      &&push_slot1_special,                                // PUSH_SLOT_NARGOUT1_SPECIAL,
+      &&disp,                                              // DISP,
+      &&push_slot_disp,                                    // PUSH_SLOT_DISP,
+      &&load_cst_alt2,                                     // LOAD_CST_ALT2,
+      &&load_cst_alt3,                                     // LOAD_CST_ALT3,
+      &&load_cst_alt4,                                     // LOAD_CST_ALT4,
+      &&load_2_cst,                                        // LOAD_2_CST,
+      &&mul_dbl,                                           // MUL_DBL,
+      &&add_dbl,                                           // ADD_DBL,
+      &&sub_dbl,                                           // SUB_DBL,
+      &&div_dbl,                                           // DIV_DBL,
+      &&pow_dbl,                                           // POW_DBL,
+      &&le_dbl,                                            // LE_DBL,
+      &&le_eq_dbl,                                         // LE_EQ_DBL,
+      &&gr_dbl,                                            // GR_DBL,
+      &&gr_eq_dbl,                                         // GR_EQ_DBL,
+      &&eq_dbl,                                            // EQ_DBL,
+      &&neq_dbl,                                           // NEQ_DBL,
+      &&index_id1_mat_1d,                                  // INDEX_ID1_MAT_1D,
+      &&index_id1_mat_2d,                                  // INDEX_ID1_MAT_2D,
+      &&push_pi,                                           // PUSH_PI,
+      &&index_math_ufun_id1,                               // INDEX_ID1_MATHY_UFUN,
+      &&subassign_id_mat_1d,                               // SUBASSIGN_ID_MAT_1D,
+      &&incr_id_prefix_dbl,                                // INCR_ID_PREFIX_DBL,
+      &&decr_id_prefix_dbl,                                // DECR_ID_PREFIX_DBL,
+      &&incr_id_postfix_dbl,                               // INCR_ID_POSTFIX_DBL,
+      &&decr_id_postfix_dbl,                               // DECR_ID_POSTFIX_DBL,
+      &&push_cst_dbl_0,                                    // PUSH_DBL_0,
+      &&push_cst_dbl_1,                                    // PUSH_DBL_1,
+      &&push_cst_dbl_2,                                    // PUSH_DBL_2,
+      &&jmp_if_bool,                                       // JMP_IF_BOOL,
+      &&jmp_ifn_bool,                                      // JMP_IFN_BOOL,
+      &&usub_dbl,                                          // USUB_DBL,
+      &&not_dbl,                                           // NOT_DBL,
+      &&not_bool,                                          // NOT_BOOL,
+      &&push_folded_cst,                                   // PUSH_FOLDED_CST,
+      &&set_folded_cst,                                    // SET_FOLDED_CST,
+      &&wide,                                              // WIDE
     };
 
   if (OCTAVE_UNLIKELY (m_profiler_enabled))
@@ -796,13 +856,15 @@
   //
   // If GCC is not nudged to put these in registers, its register allocator
   // might make the VM spend quite some time pushing and popping of the C-stack.
+  register int arg0 asm("r12");
   register stack_element *sp asm("r14");    // Stack pointer register
   register unsigned char *ip asm("r15");    // The instruction pointer register
   register stack_element *bsp asm("r13");   // Base stack pointer
 #else
-   stack_element *sp;
-   unsigned char *ip;
-   stack_element *bsp;
+  int arg0;
+  stack_element *sp;
+  unsigned char *ip;
+  stack_element *bsp;
 #endif
 
   unsigned char *code; // The instruction base register
@@ -822,12 +884,12 @@
   {
 #define N_RETURNS() static_cast<signed char>(code[0])
 #define N_ARGS() static_cast<signed char>(code[1])
-#define N_LOCALS() code[2]
+#define N_LOCALS() (code[2] | (code [3] << 8))
 
     int n_returns = static_cast<signed char> (*ip++);
     // n_args is negative for varargin calls
     int n_args = static_cast<signed char> (*ip++);
-    int n_locals = *ip++; // Note: An arg and return can share slot
+    int n_locals = POP_CODE_USHORT (); // Note: An arg and return can share slot
 
     bool is_varargin = n_args < 0;
     bool is_varargout = n_returns < 0;
@@ -898,12 +960,14 @@
       {
         (*sp++).pee = new execution_exception {"error","","function called with too many inputs"};
         (*sp++).i = static_cast<int> (error_type::EXECUTION_EXC);
+        ip++; // unwind expects ip to point to two after the opcode being executed
         goto unwind;
       }
     if (!is_varargout && root_nargout > n_returns - 1) // n_returns includes %nargout, so subtract one
       {
         (*sp++).pee = new execution_exception {"error","","function called with too many outputs"};
         (*sp++).i = static_cast<int> (error_type::EXECUTION_EXC);
+        ip++;
         goto unwind;
       }
 
@@ -917,18 +981,18 @@
 pop:
   {
     (*--sp).ov.~octave_value ();
-    DISPATCH ();
+    DISPATCH_1BYTEOP ();
   }
 dup:
   {
     new (sp) octave_value ((sp[-1]).ov);
     sp++;
-    DISPATCH ();
+    DISPATCH_1BYTEOP ();
   }
 load_cst:
   {
     // The next instruction is the offset in the data.
-    int offset = *ip++;
+    int offset = arg0;
 
     // Copy construct it into the top of the stack
     new (sp++) octave_value (data [offset]);
@@ -937,28 +1001,28 @@
   }
 mul_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_mul, mul, MUL, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 mul:
   MAKE_BINOP_SELFMODIFYING (binary_op::op_mul, mul_dbl, MUL_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 div_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_div, div, DIV, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 div:
   MAKE_BINOP_SELFMODIFYING (binary_op::op_div, div_dbl, DIV_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 add_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_add, add, ADD, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 add:
   MAKE_BINOP_SELFMODIFYING (binary_op::op_add, add_dbl, ADD_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 sub_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_sub, sub, SUB, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 sub:
   MAKE_BINOP_SELFMODIFYING (binary_op::op_sub, sub_dbl, SUB_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 ret:
   {
     // We need to tell the bytecode frame we are unwinding so that it can save
@@ -1179,7 +1243,7 @@
 assign:
   {
     // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value_vm &ov_rhs = TOP_OV_VM ();
     octave_value_vm &ov_lhs = bsp[slot].ov_vm;
@@ -1201,7 +1265,7 @@
 assign_dispath:
 {
   // Extract the slot number again
-  int slot = ip[-1];
+  int slot = arg0;
 
   octave_value &ov_rhs = TOP_OV ();
   octave_value &ov_lhs = bsp[slot].ov;
@@ -1260,11 +1324,11 @@
   if (OCTAVE_UNLIKELY (ov_1.type_id () != m_bool_typeid))
     {
       // Change the specialized opcode to the generic one
-      ip[-1] = static_cast<unsigned char> (INSTR::JMP_IF);
+      ip[-2] = static_cast<unsigned char> (INSTR::JMP_IF);
       goto jmp_if;
     }
 
-  unsigned char b0 = *ip++;
+  unsigned char b0 = arg0;
   unsigned char b1 = *ip++;
 
   int target = b0 | (b1 << 8);
@@ -1288,11 +1352,11 @@
     if (OCTAVE_UNLIKELY (ov_1.type_id () == m_bool_typeid))
       {
         // Change the generic opcode to the specialized one
-        ip[-1] = static_cast<unsigned char> (INSTR::JMP_IF_BOOL);
+        ip[-2] = static_cast<unsigned char> (INSTR::JMP_IF_BOOL);
         goto jmp_if_bool;
       }
 
-    unsigned char b0 = *ip++;
+    unsigned char b0 = arg0;
     unsigned char b1 = *ip++;
 
     int target = b0 | (b1 << 8);
@@ -1304,8 +1368,11 @@
           {
             is_true = ov_1.is_true ();
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
+        CATCH_BAD_ALLOC
+        CATCH_EXIT_EXCEPTION
       }
     else
       {
@@ -1321,7 +1388,7 @@
   DISPATCH();
 jmp:
   {
-    unsigned char b0 = *ip++;
+    unsigned char b0 = arg0;
     unsigned char b1 = *ip++;
 
     int target = b0 | (b1 << 8);
@@ -1335,11 +1402,11 @@
   if (OCTAVE_UNLIKELY (ov_1.type_id () != m_bool_typeid))
     {
       // Change the specialized opcode to the generic one
-      ip[-1] = static_cast<unsigned char> (INSTR::JMP_IFN);
+      ip[-2] = static_cast<unsigned char> (INSTR::JMP_IFN);
       goto jmp_ifn;
     }
 
-  unsigned char b0 = *ip++;
+  unsigned char b0 = arg0;
   unsigned char b1 = *ip++;
 
   int target = b0 | (b1 << 8);
@@ -1363,11 +1430,11 @@
     if (OCTAVE_UNLIKELY (ov_1.type_id () == m_bool_typeid))
       {
         // Change the generic opcode to the specialized one
-        ip[-1] = static_cast<unsigned char> (INSTR::JMP_IFN_BOOL);
+        ip[-2] = static_cast<unsigned char> (INSTR::JMP_IFN_BOOL);
         goto jmp_ifn_bool;
       }
 
-    unsigned char b0 = *ip++;
+    unsigned char b0 = arg0;
     unsigned char b1 = *ip++;
 
     int target = b0 | (b1 << 8);
@@ -1379,8 +1446,11 @@
           {
             is_true = ov_1.is_true ();
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
+        CATCH_BAD_ALLOC
+        CATCH_EXIT_EXCEPTION
       }
     else
       {
@@ -1393,11 +1463,11 @@
     if (!is_true)
       ip = code + target;
   }
-  DISPATCH();
+  DISPATCH ();
 push_slot_nargoutn:
   {
     // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
@@ -1415,12 +1485,39 @@
       PUSH_OV (ov.ref_rep ()->deref ()); // global, persistent ... need dereferencing
   }
   DISPATCH();
+set_folded_cst:
+{
+  int slot = arg0;
+  octave_cached_value *ovb = static_cast<octave_cached_value*> (bsp[slot].ovb);
+  ovb->set_cached_obj (std::move (TOP_OV ()));
+  STACK_DESTROY (1);
+}
+DISPATCH();
+push_folded_cst:
+  {
+    int slot = arg0;
+    unsigned char b0 = *ip++;
+    unsigned char b1 = *ip++;
+  
+    octave_cached_value *ovb = static_cast<octave_cached_value*> (bsp[slot].ovb);
+    if (ovb->is_defined () && ovb->cache_is_valid ())
+      {
+        PUSH_OV (ovb->get_cached_value ());
+        int target = b0 | (b1 << 8);
+        ip = code + target;
+      }
+    else
+      {
+        bsp[slot].ov = octave_value {new octave_cached_value};
+      }
+  }
+  DISPATCH();
+
 push_slot_nargout0:
 push_slot_nargout1:
 push_slot1_special:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_base_value *ovb = bsp[slot].ovb;
 
@@ -1434,8 +1531,7 @@
 // This is not an op-code and is only jumped to from above opcode.
 push_slot_dispatch:
   {
-    // Reread the slot number
-    int slot = ip[-1];
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
@@ -1459,8 +1555,8 @@
     octave_value &ov = TOP_OV ();
     // 0 is magic slot number that indicates no name or always not a command
     // for this opcode.
-    int slot = *ip++;
-    int slot_was_cmd = *ip++; // Marker for if the preceding call was a command call
+    int slot = arg0;
+    int slot_was_cmd = POP_CODE_USHORT (); // Marker for if the preceding call was a command call
 
     bool call_was_cmd = false;
     if (slot_was_cmd)
@@ -1488,9 +1584,11 @@
                   {
                     interp.feval ("display", el_ovl);
                   }
+                CATCH_INTERRUPT_EXCEPTION
                 CATCH_INDEX_EXCEPTION
                 CATCH_EXECUTION_EXCEPTION
                 CATCH_BAD_ALLOC
+                CATCH_EXIT_EXCEPTION
               }
           }
         else
@@ -1511,9 +1609,12 @@
               {
                 interp.feval ("display", ovl);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
       }
 
@@ -1523,9 +1624,8 @@
 
 push_slot_disp:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
-    int slot_was_cmd = *ip++;
+    int slot = arg0;
+    int slot_was_cmd = POP_CODE_USHORT ();
     octave_value &ov = bsp[slot].ov;
     octave_value &ov_was_cmd = bsp[slot_was_cmd].ov;
 
@@ -1533,15 +1633,19 @@
     // I.e. cmd fn calls or classdef metas.
     // Also error if no function-ish thing is found
     // in lookups.
+
+    // Assume that the pushed slot will not be a cmd.
+    // disp will later use the ov_was_cmd slot to choose between printing
+    // 'ans = ...' or 'foo = ...'
+    ov_was_cmd = octave_value ();
+
     if (ov.is_maybe_function ())
       {
         if (ov.is_undefined ()) // class objects are defined
-          ov_was_cmd = true;
-        ip--; // cmd_fcn_or_undef_error: looks for the opcode in ip[-1]
+          ov_was_cmd = true; 
+        ip -= 2; // Rewind to slot so the state matches 'push_slot_nargoutn' and 'push_slot_dispatch'.
         goto cmd_fcn_or_undef_error;
       }
-    else
-      ov_was_cmd = octave_value ();
 
     // Push the value in the slot to the stack
     if (OCTAVE_LIKELY (!ov.is_ref ()))
@@ -1554,14 +1658,14 @@
 // Some kludge to handle the possibility of command form function calls.
 cmd_fcn_or_undef_error:
   {
-    // Need the slot number
-    int slot = *(ip - 1);
+    int slot = arg0;
     octave_value ov = bsp[slot].ov;
     bool is_ref = ov.is_ref ();
     if (is_ref)
       ov = ov.ref_rep ()->deref ();
 
-    // Check to opcode to see how many nargout there are
+    // Check to opcode to see how many nargout there are.
+    // Also skip ip to the end of the opcode.
     int nargout;
     bool push_classdef_metas = false;
     INSTR opcode = static_cast<INSTR> (*(ip - 2));
@@ -1580,7 +1684,7 @@
     else if (opcode == INSTR::PUSH_SLOT_DISP)
       {
         nargout = 0;
-        ip++; // Skip the maybe command slot
+        ip += 2; // Skip the maybe command slot
       }
     else
       PANIC ("Invalid opcode");
@@ -1636,9 +1740,12 @@
 
                 EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (ovl, nargout);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
         else
           PUSH_OV (ov); // TODO: The walker does this. Sane?
@@ -1649,46 +1756,46 @@
   DISPATCH ();
 le_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_le, le, LE, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP ();
 le:
   MAKE_BINOP_SELFMODIFYING (binary_op::op_lt, le_dbl, LE_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP ();
 le_eq_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_le_eq, le_eq, LE_EQ, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 le_eq:
   MAKE_BINOP_SELFMODIFYING(binary_op::op_le, le_eq_dbl, LE_EQ_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 gr_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_gr, gr, GR, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 gr:
   MAKE_BINOP_SELFMODIFYING(binary_op::op_gt, gr_dbl, GR_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 gr_eq_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_gr_eq, gr_eq, GR_EQ, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 gr_eq:
   MAKE_BINOP_SELFMODIFYING(binary_op::op_ge, gr_eq_dbl, GR_EQ_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 eq_dbl:
   MAKE_BINOP_SPECIALIZED(m_fn_dbl_eq, eq, EQ, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 eq:
   MAKE_BINOP_SELFMODIFYING(binary_op::op_eq, eq_dbl, EQ_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 neq_dbl:
   MAKE_BINOP_SPECIALIZED(m_fn_dbl_neq, neq, NEQ, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 neq:
   MAKE_BINOP_SELFMODIFYING(binary_op::op_ne, neq_dbl, NEQ_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 
 
 index_id1_mat_1d:
 {
+  int slot = arg0;
   ip++; // n_args_on_stack ignored
-  int slot = *ip++;
 
   octave_base_value *arg1 = TOP_OVB ();
   octave_value &mat = SEC_OV ();
@@ -1698,10 +1805,11 @@
   // If the args have change types we need to use the generic index opcode
   if (OCTAVE_UNLIKELY (!is_scalar || !is_mat))
     {
-      // Rewind ip to the 2nd byte of the opcode
-      ip -= 2;
+      // Rewind ip ton_args_on_stack
+      ip -= 1;
+      int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
       // Change the specialized opcode to the generic one
-      ip[-1] = static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1);
+      ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1);
       goto index_id1;
     }
 
@@ -1724,16 +1832,18 @@
       STACK_DESTROY (2);
       PUSH_OV (std::move (ans));
     }
+  CATCH_INTERRUPT_EXCEPTION
   CATCH_INDEX_EXCEPTION_WITH_NAME
   CATCH_EXECUTION_EXCEPTION
   CATCH_BAD_ALLOC
+  CATCH_EXIT_EXCEPTION
 }
 DISPATCH();
 
 index_id1_mat_2d:
 {
+  int slot = arg0;
   ip++; // n_args_on_stack ignored
-  int slot = *ip++;
 
   octave_base_value *arg2 = TOP_OVB (); // Collumn index
   octave_base_value *arg1 = SEC_OVB (); // Row index
@@ -1747,10 +1857,11 @@
   // If the args have change types we need to use the generic index opcode
   if (OCTAVE_UNLIKELY (!is_scalar || !is_mat))
     {
-      // Rewind ip to the 2nd byte of the opcode
-      ip -= 2;
+      // Rewind ip to n_args_on_stack
+      ip -= 1;
+      int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
       // Change the specialized opcode to the generic one
-      ip[-1] = static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1);
+      ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1);
       goto index_id1;
     }
 
@@ -1785,25 +1896,29 @@
       STACK_DESTROY (3);
       PUSH_OV (std::move (ans));
     }
+  CATCH_INTERRUPT_EXCEPTION
   CATCH_INDEX_EXCEPTION_WITH_NAME
   CATCH_EXECUTION_EXCEPTION
   CATCH_BAD_ALLOC
+  CATCH_EXIT_EXCEPTION
 }
 DISPATCH();
 
 index_math_ufun_id1:
 {
-  auto ufn = static_cast<octave_base_value::unary_mapper_t> (*ip++);
+  auto ufn = static_cast<octave_base_value::unary_mapper_t> (arg0);
+  ip++; // slot number ignored
   ip++; // "n_args_on_stack" ignored. Always 1
-  ip++; // slot number ignored
+
   // The object to index is before the arg on the stack
   octave_value &arg = TOP_OV ();
   octave_value &ov = SEC_OV ();
 
-  if (arg.type_id () != m_scalar_typeid ||
-      !ov.is_function_cache ())
+  if (OCTAVE_UNLIKELY (arg.type_id () != m_scalar_typeid ||
+      !ov.is_function_cache ()))
     {
-      ip -= 2;
+      ip -= 1; // Rewind ip to n_args_on_stack
+      arg0 = ip[-1]; // set arg0 to slot
       goto index_math_ufun_id1_dispatch;
     }
 
@@ -1816,9 +1931,10 @@
     }
   CATCH_EXECUTION_EXCEPTION // parse errors might throw in classdefs
 
-  if (!fcn->is_builtin_function ())
+  if (OCTAVE_UNLIKELY (!fcn->is_builtin_function ()))
     {
-      ip -= 2;
+      ip -= 1; // Rewind ip to n_args_on_stack
+      arg0 = ip[-1]; // set arg0 to slot
       goto index_math_ufun_id1_dispatch;
     }
 
@@ -1836,16 +1952,15 @@
 // is used instead.
 {
   // The next instruction is the slot number
-  int slot = *ip++;
+  int slot = arg0;
 
   octave_value &ov = bsp[slot].ov;
   // If the slot value is not a function cache we do a
   // PUSH_SLOT_NARGOUT1 which will most likely put a
   // function cache in the slot (unless the user has done a
   // "pi = 123;" or whatever).
-  if (!ov.is_function_cache ())
+  if (OCTAVE_UNLIKELY (!ov.is_function_cache ()))
     {
-      ip--;
       goto push_slot_nargout1;
     }
 
@@ -1857,9 +1972,8 @@
     }
   CATCH_EXECUTION_EXCEPTION // parse errors might throw in classdefs
 
-  if (fcn != m_pi_builtin_fn)
+  if (OCTAVE_UNLIKELY (fcn != m_pi_builtin_fn))
     {
-      ip--;
       goto push_slot_nargout1;
     }
 
@@ -1872,35 +1986,39 @@
     // TODO: Too much code. Should be broken out?
 
     // Note: Beutifully interleaved if branches and goto labels
-    int nargout;
+    int nargout, slot;
     bool specialization_ok;
     if (0)
       {
 index_idn:
+        slot = arg0; // Needed if we need a function lookup
         nargout = *ip++;
         specialization_ok = false;
       }
     else if (0)
       {
 index_id1:
+        slot = arg0;
         nargout = 1;
         specialization_ok = true;
       }
     else if (0)
       {
 index_id_nargout0:
+        slot = arg0;
         nargout = 0;
         specialization_ok = false;
       }
     else
       {
 index_math_ufun_id1_dispatch: // Escape dispatch for index_math_ufun_id1 specialization
+        slot = arg0;
         nargout = 1;
         specialization_ok = false;
       }
 
     int n_args_on_stack = *ip++;
-    int slot = *ip++; // Needed if we need a function lookup
+
     // The object to index is before the args on the stack
     octave_value &ov = (sp[-1 - n_args_on_stack]).ov;
 
@@ -1934,16 +2052,22 @@
       {
         if (n_args_on_stack == 1)
           {
-            ip -= 2;
-            CHECK (ip[-1] == static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1));
-            ip[-1] = static_cast<unsigned char> (INSTR::INDEX_ID1_MAT_1D);
+            ip -= 1;
+            int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+            
+            CHECK (ip[-2 + wide_opcode_offset] == static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1));
+            ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INDEX_ID1_MAT_1D);
+
             goto index_id1_mat_1d;
           }
         else if (n_args_on_stack == 2)
           {
-            ip -= 2;
-            CHECK (ip[-1] == static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1));
-            ip[-1] = static_cast<unsigned char> (INSTR::INDEX_ID1_MAT_2D);
+            ip -= 1;
+            int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+
+            CHECK (ip[-2 + wide_opcode_offset] == static_cast<unsigned char> (INSTR::INDEX_ID_NARGOUT1));
+            ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INDEX_ID1_MAT_2D);
+
             goto index_id1_mat_2d;
           }
       }
@@ -1967,9 +2091,12 @@
                 retval = ov.simple_subsref ('(', ovl, nargout);
                 ovl.clear ();
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION_WITH_NAME
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
         else
           TODO ("Silly state");
@@ -2017,9 +2144,11 @@
                 STACK_DESTROY (n_args_on_stack + 1);
                 EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (ret, nargout);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
           }
       }
     else
@@ -2042,7 +2171,7 @@
 push_slot_indexed:
   {
     // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
     octave_value &ov = bsp[slot].ov;
 
     // Unlike push_slot this can't be a command function call
@@ -2059,39 +2188,39 @@
 
 pow_dbl:
   MAKE_BINOP_SPECIALIZED (m_fn_dbl_pow, pow, POW, m_scalar_typeid)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 pow:
   MAKE_BINOP_SELFMODIFYING(binary_op::op_pow, pow_dbl, POW_DBL)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 ldiv:
   MAKE_BINOP(binary_op::op_ldiv)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 el_mul:
   MAKE_BINOP(binary_op::op_el_mul)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 el_div:
   MAKE_BINOP(binary_op::op_el_div)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 el_pow:
   MAKE_BINOP(binary_op::op_el_pow)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 el_and:
   MAKE_BINOP(binary_op::op_el_and)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 el_or:
   MAKE_BINOP(binary_op::op_el_or)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 el_ldiv:
   MAKE_BINOP(binary_op::op_el_ldiv)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 
 not_dbl:
 MAKE_UNOP_SPECIALIZED (m_fn_dbl_not, op_not, NOT, m_scalar_typeid);
-DISPATCH ();
+DISPATCH_1BYTEOP ();
 
 not_bool:
 MAKE_UNOP_SPECIALIZED (m_fn_bool_not, op_not, NOT, m_bool_typeid);
-DISPATCH ();
+DISPATCH_1BYTEOP ();
 
 op_not:
   {
@@ -2101,13 +2230,13 @@
     if (OCTAVE_UNLIKELY (type_id == m_scalar_typeid))
       {
         // Change the generic opcode to the specialized one
-        ip[-1] = static_cast<unsigned char> (INSTR::NOT_DBL);
+        ip[-2] = static_cast<unsigned char> (INSTR::NOT_DBL);
         goto not_dbl;
       }
     else if (OCTAVE_UNLIKELY (type_id == m_bool_typeid))
       {
         // Change the generic opcode to the specialized one
-        ip[-1] = static_cast<unsigned char> (INSTR::NOT_BOOL);
+        ip[-2] = static_cast<unsigned char> (INSTR::NOT_BOOL);
         goto not_bool;
       }
 
@@ -2121,11 +2250,13 @@
 
         new (sp++) octave_value (std::move (ans));
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 uadd:
   {
     octave_value &ov = TOP_OV ();
@@ -2140,15 +2271,17 @@
 
         new (sp++) octave_value (std::move (ans));
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 
 usub_dbl:
 MAKE_UNOP_SPECIALIZED (m_fn_dbl_usub, usub, USUB, m_scalar_typeid);
-DISPATCH ();
+DISPATCH_1BYTEOP ();
 usub:
   {
     octave_value &ov = TOP_OV ();
@@ -2156,7 +2289,7 @@
     if (OCTAVE_UNLIKELY (ov.type_id () == m_scalar_typeid))
       {
         // Change the generic opcode to the specialized one
-        ip[-1] = static_cast<unsigned char> (INSTR::USUB_DBL);
+        ip[-2] = static_cast<unsigned char> (INSTR::USUB_DBL);
         goto usub_dbl;
       }
 
@@ -2170,11 +2303,13 @@
 
         new (sp++) octave_value (std::move (ans));
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 trans:
   {
     octave_value &ov = TOP_OV ();
@@ -2190,11 +2325,13 @@
 
         new (sp++) octave_value (std::move (ans));
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 herm:
   {
     octave_value &ov = TOP_OV ();
@@ -2210,25 +2347,26 @@
 
         new (sp++) octave_value (std::move (ans));
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 
 incr_id_prefix_dbl:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () != m_scalar_typeid)
       {
-        ip -= 1;
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
         // Change the specialized opcode to the generic one
-        ip[-1] = static_cast<unsigned char> (INSTR::INCR_ID_PREFIX);
-        goto decr_id_prefix;
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INCR_ID_PREFIX);
+        goto incr_id_prefix;
       }
 
     octave_scalar &scalar = REP (octave_scalar, ov);
@@ -2242,16 +2380,15 @@
   DISPATCH();
 incr_id_prefix:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () == m_scalar_typeid)
       {
-        ip -= 1;
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
         // Change the generic opcode to the specialized one
-        ip[-1] = static_cast<unsigned char> (INSTR::INCR_ID_PREFIX_DBL);
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INCR_ID_PREFIX_DBL);
         goto incr_id_prefix_dbl;
       }
 
@@ -2269,23 +2406,24 @@
             PUSH_OV (ov_glb);
           }
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
   DISPATCH();
 
 decr_id_prefix_dbl:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () != m_scalar_typeid)
       {
-        ip -= 1;
-        ip[-1] = static_cast<unsigned char> (INSTR::DECR_ID_PREFIX);
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::DECR_ID_PREFIX);
         goto decr_id_prefix;
       }
 
@@ -2300,15 +2438,14 @@
   DISPATCH();
 decr_id_prefix:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () == m_scalar_typeid)
       {
-        ip -= 1;
-        ip[-1] = static_cast<unsigned char> (INSTR::DECR_ID_PREFIX_DBL);
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::DECR_ID_PREFIX_DBL);
         goto decr_id_prefix_dbl;
       }
 
@@ -2326,22 +2463,23 @@
             PUSH_OV (ov_glb);
           }
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
   DISPATCH();
 incr_id_postfix_dbl:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () != m_scalar_typeid)
       {
-        ip -= 1;
-        ip[-1] = static_cast<unsigned char> (INSTR::INCR_ID_POSTFIX);
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INCR_ID_POSTFIX);
         goto incr_id_postfix;
       }
 
@@ -2354,15 +2492,14 @@
   DISPATCH();
 incr_id_postfix:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () == m_scalar_typeid)
       {
-        ip -= 1;
-        ip[-1] = static_cast<unsigned char> (INSTR::INCR_ID_POSTFIX_DBL);
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::INCR_ID_POSTFIX_DBL);
         goto incr_id_postfix_dbl;
       }
 
@@ -2382,22 +2519,23 @@
             PUSH_OV (std::move (copy));
           }
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
   DISPATCH();
 decr_id_postfix_dbl:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () != m_scalar_typeid)
       {
-        ip -= 1;
-        ip[-1] = static_cast<unsigned char> (INSTR::DECR_ID_POSTFIX);
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::DECR_ID_POSTFIX);
         goto decr_id_postfix;
       }
 
@@ -2410,15 +2548,14 @@
   DISPATCH();
 decr_id_postfix:
   {
-    // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov = bsp[slot].ov;
 
     if (ov.type_id () == m_scalar_typeid)
       {
-        ip -= 1;
-        ip[-1] = static_cast<unsigned char> (INSTR::DECR_ID_POSTFIX_DBL);
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+        ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::DECR_ID_POSTFIX_DBL);
         goto decr_id_postfix_dbl;
       }
 
@@ -2438,9 +2575,11 @@
             PUSH_OV (std::move (copy));
           }
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
   DISPATCH();
 for_setup:
@@ -2449,8 +2588,9 @@
 
     octave_idx_type n = ov_range.numel();
 
+    bool is_range = ov_range.is_range ();
     //TODO: Kludge galore. Should be refactored into some virtual call.
-    if ((ov_range.is_range ()) &&
+    if (is_range &&
         (
          ov_range.is_double_type () ||
          ov_range.is_int64_type () ||
@@ -2467,7 +2607,7 @@
       {
         ov_range = ov_range.maybe_as_trivial_range ();
       }
-    else if (ov_range.is_range () ||
+    else if (is_range ||
              ov_range.is_matrix_type () ||
              ov_range.iscell () ||
              ov_range.is_string () ||
@@ -2488,7 +2628,17 @@
       TODO ("Unsupported for rhs type");
 
     // TODO: Kludgy classes.
-    // TODO: print "inf" warning here
+
+    if (!ov_range.is_trivial_range () && is_range)
+      {
+        // TODO: Wasteful copy of range.
+        auto range = ov_range.range_value ();
+        if (math::isinf (range.limit ()) || math::isinf (range.base ()))
+            warning_with_id ("Octave:infinite-loop",
+                     "FOR loop limit is infinite, will stop after %"
+                     OCTAVE_IDX_TYPE_FORMAT " steps", range.numel ());
+      }
+
 
     // Push n to the stack
     (*sp++).i = n;
@@ -2500,7 +2650,11 @@
     if (! n)
       {
         // Slot from the for_cond that always follow a for_setup
-        int slot = *(ip + 3);
+        int slot;
+        if (arg0 == static_cast<int> (INSTR::WIDE))
+          slot = ip[1];
+        else
+          slot = ip[0];
         try
         {
           octave_value &lhs_ov = bsp[slot].ov;
@@ -2511,12 +2665,9 @@
         }
         CATCH_EXECUTION_EXCEPTION
       }
-
-    // The next opcode will be FOR_COND implictly.
-    // We will just fall through to it and point ip
-    // to FOR_COND's first operand.
-    ip++;
   }
+DISPATCH_1BYTEOP ();
+
 for_cond:
   {
     // Check if we should exit the loop due to e.g. ctrl-c, or handle
@@ -2525,24 +2676,22 @@
       {
         octave_quit ();
       }
-    catch (interrupt_exception &e)
-      {
-        (*sp++).i = static_cast<int>(error_type::INTERRUPT_EXC);
-        goto unwind;
-      }
+    CATCH_INTERRUPT_EXCEPTION
+    CATCH_INDEX_EXCEPTION
+    CATCH_EXECUTION_EXCEPTION
+    CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     // Increase counter
     TOP ().i++; // Wraps to zero first iteration
-
-    ip +=2; // Skip the after address
-
+    
     // Check if we done all iterations
     // n is second element on the stack
     if (TOP ().i == SEC ().i)
       {
         // The after address
-        unsigned char b0 = *(ip - 2);
-        unsigned char b1 = *(ip - 1);
+        unsigned char b0 = *ip++;
+        unsigned char b1 = *ip++;
 
         int after = b0 | (b1 << 8);
 
@@ -2552,7 +2701,9 @@
     else
       {
         // Write the iteration's value to the for loop variable
-        int slot = *ip++;
+        int slot = arg0;
+        ip +=2; // Skip the after address
+
         octave_idx_type counter = TOP ().i;
 
         octave_value &ov_range = THIRD_OV ();
@@ -2580,12 +2731,12 @@
   DISPATCH ();
 pop_n_ints:
   {
-    sp -= *ip++;
+    sp -= arg0;
     DISPATCH();
   }
 push_fcn_handle:
   {
-    int slot = *ip++;
+    int slot = arg0;
 
     //octave_value &fcn_cache = bsp[slot].ov;
 
@@ -2617,8 +2768,8 @@
       }
 
     bool has_incr = false;
-    if (*(ip - 1) == static_cast<int> (INSTR::COLON3) ||
-        *(ip - 1) == static_cast<int> (INSTR::COLON3_CMD))
+    if (ip[-2] == static_cast<int> (INSTR::COLON3) ||
+        ip[-2] == static_cast<int> (INSTR::COLON3_CMD))
       has_incr = true;
 
     octave_value ret;
@@ -2633,6 +2784,7 @@
         {
           ret = colon_op(base, incr, limit, is_for_cmd);
         }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
 
@@ -2647,6 +2799,7 @@
         {
           ret = colon_op(base, limit, is_for_cmd);
         }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
 
@@ -2655,18 +2808,18 @@
 
     PUSH_OV (std::move (ret));
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 
 push_true:
   {
     PUSH_OV(ov_true);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 push_false:
   {
     PUSH_OV(ov_false);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 unary_true:
   {
     octave_value &op1 = TOP_OV ();
@@ -2677,8 +2830,11 @@
       {
         is_true = op1.is_true ();
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
+    CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     STACK_DESTROY (1);
 
@@ -2688,10 +2844,10 @@
       PUSH_OV (ov_false);
 
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 assign_n:
   {
-    int n_slots = *ip++;
+    int n_slots = arg0;
 
     int n_actual = 0;
     do
@@ -2699,7 +2855,7 @@
         // Move operand to the local at slot in relation to base stack pointer
 
         octave_value &arg = (*--sp).ov;
-        int slot = *ip++;
+        int slot = POP_CODE_USHORT ();
         octave_value &lhs_ov = bsp[slot].ov;
 
 
@@ -2809,8 +2965,8 @@
 
 subassign_id_mat_1d:
 {
+  int slot = arg0;
   ip++; // nargs always one
-  int slot = *ip++;
 
   // The top of the stack is the rhs value
   octave_value &rhs = TOP_OV ();
@@ -2826,9 +2982,10 @@
     arg_type_id != m_scalar_typeid)
   {
     // Rewind ip to the 2nd byte of the opcode
-    ip -= 2;
+    ip -= 1;
+    int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
     // Change the specialized opcode to the general one
-    ip[-1] = static_cast<unsigned char> (INSTR::SUBASSIGN_ID);
+    ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::SUBASSIGN_ID);
     goto subassign_id;
   }
 
@@ -2850,7 +3007,7 @@
           idx != idx_dbl - 1)
         {
           // Rewind ip to the 2nd byte of the opcode
-          ip -= 2;
+          ip -= 1;
           goto subassign_id;
         }
 
@@ -2859,9 +3016,11 @@
 
       arr.xelem (idx) = val;
     }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION_WITH_NAME
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
   STACK_DESTROY (2);
 }
@@ -2870,8 +3029,8 @@
 subassign_id:
   {
     // The args to the subassign are on the operand stack
+    int slot = arg0;
     int nargs = *ip++;
-    int slot = *ip++;
 
     // The top of the stack is the rhs value
     octave_value &rhs = TOP_OV ();
@@ -2900,14 +3059,16 @@
     if (nargs == 1 && all_args_are_scalar && ov.type_id () == m_matrix_typeid &&
         rhs.type_id () == m_scalar_typeid)
       {
+        int wide_opcode_offset = slot < 256 ? 0 : -1; // If WIDE is used, we need to look further back
+
         // If the opcode allready is SUBASSIGN_ID_MAT_1D we were sent back to
         // SUBASSIGN_ID to handle some error or edgecase, so don't go back.
-        if ( ip[-3] != static_cast<unsigned char> (INSTR::SUBASSIGN_ID_MAT_1D))
+        if ( ip[-3 + wide_opcode_offset] != static_cast<unsigned char> (INSTR::SUBASSIGN_ID_MAT_1D))
           {
             // Rewind ip to the 2nd byte of the opcode
-            ip -= 2;
+            ip -= 1;
             // Change the general opcode to the specialized one
-            ip[-1] = static_cast<unsigned char> (INSTR::SUBASSIGN_ID_MAT_1D);
+            ip[-2 + wide_opcode_offset] = static_cast<unsigned char> (INSTR::SUBASSIGN_ID_MAT_1D);
             goto subassign_id_mat_1d;
           }
       }
@@ -2941,10 +3102,11 @@
       {
         ov = ov.simple_subsasgn('(', args, rhs);
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION_WITH_NAME
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
-
+    CATCH_EXIT_EXCEPTION
 
     // Destroy the args on the operand stack aswell as rhs
     STACK_DESTROY (nargs + 1);
@@ -2953,6 +3115,8 @@
 
 end_id:
   {
+    // Indexed variable
+    int slot = arg0;
     // Amount of args to the index, i.e. amount of dimensions
     // being indexed.
     // E.g. foo (1,2,3) => 3
@@ -2960,8 +3124,6 @@
     // Index of the end, in the index, counting from 0.
     // E.g. foo (1, end, 3) => 1
     int idx = *ip++;
-    // Indexed variable
-    int slot = *ip++;
 
     octave_value ov = bsp[slot].ov;
 
@@ -2982,9 +3144,11 @@
           {
             end_idx = handle_object_end (ov, idx, nargs);
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
         CATCH_BAD_ALLOC
+        CATCH_EXIT_EXCEPTION
       }
     else
       end_idx = octave_value (ov.end_index (idx, nargs));
@@ -2994,6 +3158,8 @@
   DISPATCH ();
 end_obj:
   {
+    // Slot that stores the stack depth of the indexed object
+    int slot = arg0;
     // Amount of args to the index, i.e. amount of dimensions
     // being indexed.
     // E.g. foo (1,2,3) => 3
@@ -3001,8 +3167,6 @@
     // Index of the end, in the index, counting from 0.
     // E.g. foo (1, end, 3) => 1
     int idx = *ip++;
-    // Slot that stores the stack depth of the indexed object
-    int slot = *ip++;
 
     octave_value &stack_depth = bsp[slot].ov;
     // Indexed object
@@ -3022,9 +3186,11 @@
           {
             end_idx = handle_object_end (ov, idx, nargs);
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
         CATCH_BAD_ALLOC
+        CATCH_EXIT_EXCEPTION
       }
     else
       end_idx = octave_value (ov.end_index (idx, nargs));
@@ -3040,7 +3206,7 @@
     // need to scan inner to outer after a defined
     // object to find the end of.
 
-    int n_ids = *ip++;
+    int n_ids = arg0;
     int i;
 
     for (i = 0; i < n_ids;)
@@ -3058,7 +3224,7 @@
         // Slot that stores:
         //    the object that is being indexed for type 0
         //    the stack depth of the indexed object for type 1
-        int slot = *ip++;
+        int slot = POP_CODE_USHORT ();
 
         octave_value ov = bsp[slot].ov;
 
@@ -3093,9 +3259,12 @@
               {
                 end_idx = handle_object_end (ov, idx, nargs);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
         else
           end_idx = octave_value (ov.end_index (idx, nargs));
@@ -3107,13 +3276,13 @@
 
     // Skip any unread objects to index
     for (; i < n_ids; i++)
-      ip += 4;
+      ip += 5;
   }
   DISPATCH ();
 
 eval:
   {
-    int nargout = POP_CODE ();
+    int nargout = arg0;
     int tree_idx = POP_CODE_INT ();
     CHECK (tree_idx < 0); // Should always be negative to mark for eval. Otherwise it is debug data
 
@@ -3127,16 +3296,18 @@
     {
       retval = te->evaluate_n (*m_tw, nargout);
     }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (retval, nargout);
   }
   DISPATCH ();
 bind_ans:
   {
-    int slot = POP_CODE ();
+    int slot = arg0;
     octave_value &ans_on_stack = TOP_OV ();
     octave_value &ans_in_slot = bsp [slot].ov;
 
@@ -3213,6 +3384,7 @@
 
 push_anon_fcn_handle:
 {
+  ip--; // Rewind ip for int macro underneath
   int tree_idx = POP_CODE_INT ();
 
   auto it = unwind_data->m_ip_to_tree.find (tree_idx);
@@ -3230,7 +3402,7 @@
 {
   octave_value &ov_rhs = TOP_OV ();
   ov_rhs.make_unique (); // TODO: Dunno if needed
-  unsigned char b0 = *ip++;
+  unsigned char b0 = arg0;
   unsigned char b1 = *ip++;
 
   int target = b0 | (b1 << 8);
@@ -3259,24 +3431,21 @@
   // Push a counter to the stack, initialized so that it will
   // increment to 0.
   (*sp++).i = -1;
-
-  // Fallthrough to cond
-  ip++;
 }
+DISPATCH ();
+
 for_complex_cond:
 {
   // Increase counter
   TOP ().i++; // Wraps to zero first iteration
 
-  ip +=2; // Skip the after address
-
   // Check if we done all iterations
   // n is second element on the stack
   if (TOP ().i == SEC ().i)
     {
       // The after address
-      unsigned char b0 = *(ip - 2);
-      unsigned char b1 = *(ip - 1);
+      unsigned char b0 = arg0;
+      unsigned char b1 = *ip++;
 
       int after = b0 | (b1 << 8);
 
@@ -3285,39 +3454,40 @@
     }
   else
     {
-        int slot_key = *ip++;
-        int slot_value = *ip++;
-        octave_idx_type counter = TOP ().i;
-
-        octave_value &ov_rhs = THIRD_OV (); // This is always a struct
-        octave_value &ov_key = bsp[slot_key].ov;
-        octave_value &ov_val = bsp[slot_value].ov;
-
-        // TODO: Abit wasteful copying map_value () each time but whatever
-        //       who uses complex for loops anyways.
-        std::string key = ov_rhs.map_value ().keys () [counter];
-        const Cell val_lst = ov_rhs.map_value ().contents (key);
-
-        octave_idx_type n = val_lst.numel ();
-        octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst);
-
-        if (counter == 0)
-          {
-            ov_val.maybe_call_dtor (); // The first iteration these could be class objects ...
-            ov_key.maybe_call_dtor ();
-          }
-
-        val.make_unique (); // TODO: Dunno if needed
-
-        if (ov_val.is_ref ())
-          ov_val.ref_rep ()->set_value (val);
-        else
-          ov_val = val;
-
-        if (ov_val.is_ref ())
-          ov_key.ref_rep ()->set_value (key);
-        else
-          ov_key = key;
+      ip++; // Skip 2nd part of afteraddress
+      int slot_key = POP_CODE_USHORT ();
+      int slot_value = POP_CODE_USHORT ();
+      octave_idx_type counter = TOP ().i;
+
+      octave_value &ov_rhs = THIRD_OV (); // This is always a struct
+      octave_value &ov_key = bsp[slot_key].ov;
+      octave_value &ov_val = bsp[slot_value].ov;
+
+      // TODO: Abit wasteful copying map_value () each time but whatever
+      //       who uses complex for loops anyways.
+      std::string key = ov_rhs.map_value ().keys () [counter];
+      const Cell val_lst = ov_rhs.map_value ().contents (key);
+
+      octave_idx_type n = val_lst.numel ();
+      octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst);
+
+      if (counter == 0)
+        {
+          ov_val.maybe_call_dtor (); // The first iteration these could be class objects ...
+          ov_key.maybe_call_dtor ();
+        }
+
+      val.make_unique (); // TODO: Dunno if needed
+
+      if (ov_val.is_ref ())
+        ov_val.ref_rep ()->set_value (val);
+      else
+        ov_val = val;
+
+      if (ov_val.is_ref ())
+        ov_key.ref_rep ()->set_value (key);
+      else
+        ov_key = key;
     }
 }
 DISPATCH ();
@@ -3325,7 +3495,7 @@
 /* For dynamic m*n matrix where m and n < 256 */
 matrix:
   {
-    int nrows = *ip++;
+    int nrows = arg0;
     int ncols = *ip++;
     int n_el = nrows * ncols;
 
@@ -3347,14 +3517,16 @@
 
         PUSH_OV (ov);
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
   DISPATCH ();
 matrix_big:
   {
-    int type = POP_CODE ();
+    int type = arg0;
 
     /* type 0 indicates a matrix that has unequal length of the rows.
      *
@@ -3392,9 +3564,11 @@
 
             PUSH_OV (ov);
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
         CATCH_BAD_ALLOC
+        CATCH_EXIT_EXCEPTION
       }
     else
       {
@@ -3420,35 +3594,38 @@
 
             PUSH_OV (ov);
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
         CATCH_BAD_ALLOC
+        CATCH_EXIT_EXCEPTION
       }
   }
   DISPATCH ();
 trans_mul:
   MAKE_BINOP(compound_binary_op::op_trans_mul)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 mul_trans:
   MAKE_BINOP(compound_binary_op::op_mul_trans)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 herm_mul:
   MAKE_BINOP(compound_binary_op::op_herm_mul)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 mul_herm:
   MAKE_BINOP(compound_binary_op::op_mul_herm)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 trans_ldiv:
   MAKE_BINOP(compound_binary_op::op_trans_ldiv)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 herm_ldiv:
   MAKE_BINOP(compound_binary_op::op_herm_ldiv)
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 wordcmd:
   {
+    int slot = arg0; // Needed if we need a function lookup
     int nargout = *ip++;
     int n_args_on_stack = *ip++;
-    int slot = *ip++; // Needed if we need a function lookup
+
     // The object to index is before the args on the stack
     octave_value &ov = (sp[-1 - n_args_on_stack]).ov;
 
@@ -3505,9 +3682,12 @@
                 STACK_DESTROY (n_args_on_stack + 1);
                 EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (ret, nargout);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION_WITH_NAME
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
       }
     else
@@ -3533,28 +3713,28 @@
       {
         octave_quit ();
       }
-    catch (interrupt_exception &e)
-      {
-        (*sp++).i = static_cast<int>(error_type::INTERRUPT_EXC);
-        goto unwind;
-      }
+    CATCH_INTERRUPT_EXCEPTION
+    CATCH_INDEX_EXCEPTION
+    CATCH_EXECUTION_EXCEPTION
+    CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 push_cst_dbl_0:
 {
   PUSH_OV (ov_dbl_0);
 }
-DISPATCH ();
+DISPATCH_1BYTEOP ();
 push_cst_dbl_1:
 {
   PUSH_OV (ov_dbl_1);
 }
-DISPATCH ();
+DISPATCH_1BYTEOP ();
 push_cst_dbl_2:
 {
   PUSH_OV (ov_dbl_2);
 }
-DISPATCH ();
+DISPATCH_1BYTEOP ();
 
 push_cell:
   {
@@ -3627,12 +3807,12 @@
 
     PUSH_OV (cell);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 push_ov_u64:
   {
     PUSH_OV (octave_int<uint64_t>{});
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 expand_cs_list:
   {
     octave_value cs = TOP_OV ();
@@ -3663,25 +3843,34 @@
     PUSH_OV (rows_ov);
     PUSH_OV (cols_ov);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 
   {
     // TODO: Too much code. Should be broken out?
     // Something made sp not be in r15.
 
-    int nargout;
+    int nargout, slot;
     if (0)
+      {
 index_cell_idn:
-      nargout = *ip++;
+        slot = arg0; // Needed if we need a function lookup
+        nargout = *ip++;
+      }
     else if (0)
 index_cell_id1:
-      nargout = 1;
+      {
+        slot = arg0;
+        nargout = 1;
+      }
     else if (0)
 index_cell_id0:
-      nargout = 0;
-
+      {
+        slot = arg0;
+        nargout = 0;
+      }
+    
     int n_args_on_stack = *ip++;
-    int slot = *ip++; // Needed if we need a function lookup
+
     // The object to index is before the args on the stack
     octave_value &ov = (sp[-1 - n_args_on_stack]).ov;
 
@@ -3732,9 +3921,12 @@
                 retval = ov.subsref("{", idx, nargout);
                 idx.clear ();
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION_WITH_NAME
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
         else
           {
@@ -3778,9 +3970,11 @@
                     m_tw->set_active_bytecode_ip (ip - code);
                     retval = fcn->call (*m_tw, nargout, final_args);
                   }
+                CATCH_INTERRUPT_EXCEPTION
                 CATCH_INDEX_EXCEPTION
                 CATCH_EXECUTION_EXCEPTION
                 CATCH_BAD_ALLOC
+                CATCH_EXIT_EXCEPTION
               }
 
             idx.clear ();
@@ -3829,9 +4023,12 @@
                 STACK_DESTROY (n_args_on_stack + 1);
                 EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (ret, nargout);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION_WITH_NAME
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
       }
     else
@@ -3857,7 +4054,7 @@
     // Inplace
     ov.non_const_unary_op (octave_value::unary_op::op_incr);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 
 rot:
   {
@@ -3867,7 +4064,7 @@
     PUSH_OV (top_ov);
     PUSH_OV (sec_ov);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 
 varargin_call:
   {
@@ -3878,11 +4075,11 @@
 
     octave_user_function *usr_fcn = static_cast<octave_user_function *> (sp[0].pv);
 
-    int n_returns_callee = static_cast<signed char> (*(ip - 3));
+    int n_returns_callee = static_cast<signed char> (ip[-4]);
     if (n_returns_callee < 0)
       n_returns_callee = -n_returns_callee;
-    int n_args_callee = -static_cast<signed char> (*(ip - 2)); // Note: Minus
-    int n_locals_callee = *(ip - 1);
+    int n_args_callee = -static_cast<signed char> (ip[-3]); // Note: Minus
+    int n_locals_callee = ip[-2] | (ip[-1] << 8);
 
     int nargout = sp[-1].i;
 
@@ -3992,7 +4189,12 @@
       PUSH_OV ();
 
     int nargin = n_args_on_callee_stack + idx_cell; // n_args_callee count includes varargin
-    m_tw->push_stack_frame(*this, usr_fcn, nargout, nargin);
+    try
+      {
+        m_tw->push_stack_frame(*this, usr_fcn, nargout, nargin);
+      }
+    CATCH_STACKPUSH_EXECUTION_EXCEPTION // Sets m_could_not_push_frame to true
+    CATCH_STACKPUSH_BAD_ALLOC
 
     /* Called fn needs to know about ignored outputs .e.g. [~, a] = foo() */
     if (m_output_ignore_data)
@@ -4021,6 +4223,7 @@
 
 unwind:
   {
+    ip--; // Rewind ip to after the opcode (i.e. arg0's position in the code)
     // Push VM state
     m_sp = sp;
     m_bsp = bsp;
@@ -4036,12 +4239,20 @@
     m_sp--;
 
     // Save current exception to the error system in handle_error ()
-    handle_error (et);
+    error_data errdat = handle_error (et);
+
+    // Only run unwind_protect code if the exception is the interrupt or OOM exception.
+    // I.e. no 'throw ... catch' code.
+    bool only_unwind_protect = et == error_type::INTERRUPT_EXC;
 
     while (1)
       {
         // Find unwind entry for current value of the instruction pointer
-        unwind_entry *entry = find_unwind_entry_for_current_state ();
+        unwind_entry *entry = find_unwind_entry_for_current_state (only_unwind_protect);
+
+        unwind_entry_type type = unwind_entry_type::INVALID;
+        if (entry)
+          type = entry->m_unwind_entry_type;
 
         // We need to figure out what stack depth we want.
         // If we are unwinding in a try catch we need to save any
@@ -4076,10 +4287,6 @@
               (*--m_sp).ov.~octave_value ();
           }
 
-        unwind_entry_type type = unwind_entry_type::INVALID;
-        if (entry)
-          type = entry->m_unwind_entry_type;
-
         if (type == unwind_entry_type::UNWIND_PROTECT ||
             type == unwind_entry_type::TRY_CATCH)
           {
@@ -4106,6 +4313,9 @@
             // clause identifier.
             PUSH_OV (err_map);
 
+            if (et == error_type::INTERRUPT_EXC)
+              m_unwinding_interrupt = true;
+
             goto bail_unwind;
           }
 
@@ -4154,8 +4364,11 @@
         // Restore the stack pointer
         sp = m_sp = m_sp[-1].pse;
 
-        // Pop dynamic stackframe
-        m_tw->pop_stack_frame ();
+        // Pop dynamic stackframe (unless it was never pushed)
+        if (!m_could_not_push_frame)
+          m_tw->pop_stack_frame ();
+        else
+          m_could_not_push_frame = false;
 
         // If we are messing with the interpreters lvalue_list due to some
         // ~ we need to restore stuff.
@@ -4174,8 +4387,11 @@
 
     m_tw->set_lvalue_list (m_original_lvalue_list);
 
+    // Rethrow exceptions out of the VM
     if (et == error_type::INTERRUPT_EXC)
       throw interrupt_exception {};
+    else if (et == error_type::EXIT_EXCEPTION)
+      throw exit_exception (errdat.m_exit_status, errdat.m_safe_to_return);
     else
       {
         error_system& es = m_tw->get_interpreter().get_error_system ();
@@ -4190,11 +4406,11 @@
   {
     // The next instruction tells whether we should init a global or persistent
     // variable.
-    global_type type = static_cast<global_type> (*ip++);
+    global_type type = static_cast<global_type> (arg0);
 
     // The next instruction is the local slot number for the global variable
-    int slot = *ip++;
-    ip++; // Not used
+    int slot = POP_CODE_USHORT();
+    POP_CODE_USHORT(); // Not used TODO: Remove. Make this opcode use WIDE
 
     std::string& name = name_data[slot];
 
@@ -4321,7 +4537,7 @@
 assign_compound:
   {
     // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
     // The next instruction is the type of compound operation
     octave_value::assign_op op =
       static_cast<octave_value::assign_op> (*ip++);
@@ -4348,9 +4564,11 @@
             glb_ref.assign (op, ov_rhs);
           }
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION_WITH_NAME
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     STACK_DESTROY (1);
   }
@@ -4358,7 +4576,7 @@
 jmp_ifdef:
   {
     octave_value &ov_1 = TOP_OV ();
-    unsigned char b0 = *ip++;
+    unsigned char b0 = arg0;
     unsigned char b1 = *ip++;
 
     int target = b0 | (b1 << 8);
@@ -4373,7 +4591,7 @@
   {
     octave_value &ov_label = TOP_OV ();
     octave_value &ov_switch = SEC_OV ();
-    unsigned char b0 = *ip++;
+    unsigned char b0 = arg0;
     unsigned char b1 = *ip++;
 
     int target = b0 | (b1 << 8);
@@ -4423,13 +4641,13 @@
     else
       PUSH_OV (ov_false);
   }
-  DISPATCH ();
+  DISPATCH_1BYTEOP ();
 
 braindead_warning:
   {
     // A slot stores whether we allready printed this warning for a particular
     // place where there could be a braindead short circuit
-    int slot = *ip++;
+    int slot = arg0;
     // The next codepoint is the type of warning
     int type = *ip++; // asci '|' or '&'
 
@@ -4454,7 +4672,7 @@
 force_assign:
   {
     // The next instruction is the slot number
-    int slot = *ip++;
+    int slot = arg0;
 
     octave_value &ov_rhs = TOP_OV ();
     octave_value &ov_lhs = bsp[slot].ov;
@@ -4476,7 +4694,7 @@
   {
     PUSH_OV(octave_value{});
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 throw_iferrorobj:
   {
     octave_value& ov_top = TOP_OV ();
@@ -4502,7 +4720,14 @@
         std::string s_msg  = msg.string_value ();
         std::string s_id = id.string_value ();
 
-        octave_map err_stack = map.contents ("stack").xmap_value ("ERR.STACK must be a struct");;
+        octave_map err_stack = map.contents ("stack").xmap_value ("ERR.STACK must be a struct");
+
+        // Are we unwinding an interrupt exception?
+        if (m_unwinding_interrupt)
+          {
+            (*sp++).i = static_cast<int>(error_type::INTERRUPT_EXC);
+            goto unwind;
+          }
 
         // On a rethrow, the C++ exception is always base class execution_exception.
         // We use rethrow_error() to recreate a stack info object from the octave_map
@@ -4523,13 +4748,13 @@
     else
       STACK_DESTROY (1);
   }
-  DISPATCH();
+  DISPATCH_1BYTEOP();
 
 index_struct_call:
   {
-    int nargout = POP_CODE ();
-    bool has_slot = *ip++; /* has_slot */
-    int slot = *ip++; /* slot */
+    int slot = arg0;
+    bool has_slot = *ip++;
+    int nargout = *ip++;
 
     int n_subs = POP_CODE ();
 
@@ -4627,9 +4852,11 @@
                       retval = fcn->call (*m_tw, step_nargout, {});
                     // TODO: Bytecode call.
                   }
+                CATCH_INTERRUPT_EXCEPTION
                 CATCH_INDEX_EXCEPTION
                 CATCH_EXECUTION_EXCEPTION
                 CATCH_BAD_ALLOC
+                CATCH_EXIT_EXCEPTION
               }
             else if (ov.is_function () && !ov.is_classdef_meta ())
               {
@@ -4648,9 +4875,11 @@
                   {
                     retval = ov.subsref (step_type.c_str (), step_idx, step_nargout);
                   }
+                CATCH_INTERRUPT_EXCEPTION
                 CATCH_INDEX_EXCEPTION_WITH_MAYBE_NAME (has_slot && cntr == 0)
                 CATCH_EXECUTION_EXCEPTION
                 CATCH_BAD_ALLOC
+                CATCH_EXIT_EXCEPTION
               }
 
             // If the first retval has zero length and we got more to go, it is an error
@@ -4698,9 +4927,11 @@
 
         idx.clear ();
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     STACK_DESTROY (1);
     EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (retval, nargout);
@@ -4709,10 +4940,10 @@
 
 index_struct_n:
   {
-    int nargout = *ip++;
-
-    int slot = *ip++; // Needed if we need a function lookup
-    int slot_for_field = *ip++;
+    int nargout = arg0;
+
+    int slot = POP_CODE_USHORT (); // Needed if we need a function lookup
+    int slot_for_field = POP_CODE_USHORT ();
 
     octave_value &ov = TOP_OV ();
 
@@ -4749,9 +4980,11 @@
 
         idx.clear ();
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION_WITH_NAME
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     STACK_DESTROY (1);
     EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (retval, nargout);
@@ -4760,8 +4993,8 @@
 
 subasgn_struct:
   {
-    int slot = *ip++;
-    int field_slot = *ip++;
+    int slot = arg0;
+    int field_slot = POP_CODE_USHORT ();
 
     // The top of the stack is the rhs value
     octave_value &rhs = TOP_OV ();
@@ -4794,9 +5027,11 @@
       {
         ov = ov.subsasgn (".", idx, rhs);
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION_WITH_NAME
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     STACK_DESTROY (1);
   }
@@ -4805,8 +5040,8 @@
 subasgn_cell_id:
   {
     // The args to the subassign are on the operand stack
+    int slot = arg0;
     int nargs = *ip++;
-    int slot = *ip++;
 
     // The top of the stack is the rhs value
     octave_value &rhs = TOP_OV ();
@@ -4845,9 +5080,11 @@
         // copy the return value to the slot.
         ov = ov.subsasgn("{", idx, rhs);
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION_WITH_NAME
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     // Destroy the args on the operand stack aswell as rhs
     STACK_DESTROY (nargs + 1);
@@ -4857,7 +5094,7 @@
 subassign_obj:
   {
     // The args to the subassign are on the operand stack
-    int nargs = *ip++;
+    int nargs = arg0;
     char type = *ip++;
 
     // First argument
@@ -4892,9 +5129,11 @@
         // copy the return value to the slot.
         lhs = lhs.subsasgn(std::string {type}, idx, rhs);
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     // We want lhs on the top of the stack after dropping all
     // the args to SUBASSIGN_OBJ, so we move it to where rhs is
@@ -4910,9 +5149,9 @@
 
 index_obj:
   {
-    int nargout = *ip++;
+    int nargout = arg0;
     int has_slot = *ip++;
-    int slot = *ip++;
+    int slot = POP_CODE_USHORT ();
     int n_args_on_stack = *ip++;
     char type = *ip++;
 
@@ -4964,9 +5203,12 @@
                 retval = ov.subsref(std::string {type}, idx, nargout);
                 idx.clear ();
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION_WITH_MAYBE_NAME (has_slot)
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
         else
           PANIC ("Strange state");
@@ -5002,9 +5244,11 @@
                     m_tw->set_active_bytecode_ip (ip - code);
                     retval = fcn->call (*m_tw, nargout, final_args);
                   }
+                CATCH_INTERRUPT_EXCEPTION
                 CATCH_INDEX_EXCEPTION_WITH_MAYBE_NAME (has_slot)
                 CATCH_EXECUTION_EXCEPTION
                 CATCH_BAD_ALLOC
+                CATCH_EXIT_EXCEPTION
               }
 
             idx.clear ();
@@ -5057,9 +5301,12 @@
                 STACK_DESTROY (n_args_on_stack + 1);
                 EXPAND_CSLIST_PUSH_N_OVL_ELEMENTS_TO_STACK (ret, nargout);
               }
+            CATCH_INTERRUPT_EXCEPTION
             CATCH_INDEX_EXCEPTION
             CATCH_EXECUTION_EXCEPTION
             CATCH_BAD_ALLOC
+            CATCH_EXIT_EXCEPTION
+
           }
       }
     else
@@ -5090,7 +5337,7 @@
   DISPATCH ();
 load_far_cst:
   {
-    // The next instruction is the offset in the data.
+    ip--;
     int offset = POP_CODE_INT ();
 
     // Copy construct it into the top of the stack
@@ -5106,7 +5353,7 @@
         m_output_ignore_data = new output_ignore_data;
       }
 
-    int n_ignored = POP_CODE ();
+    int n_ignored = arg0;
     int n_total = POP_CODE ();
     auto *M = new Matrix {};
     m_output_ignore_data->m_v_matrixes.push_back (M);
@@ -5162,10 +5409,10 @@
       }
 
     // Clear any value written to the %~X slot(s)
-    int n_slots = POP_CODE ();
+    int n_slots = arg0;
     for (int i = 0; i < n_slots; i++)
       {
-        int slot = POP_CODE ();
+        int slot = POP_CODE_USHORT ();
 
         octave_value &ov = bsp[slot].ov;
 
@@ -5179,7 +5426,7 @@
 
 subassign_chained:
   {
-    octave_value::assign_op op = static_cast<octave_value::assign_op> (POP_CODE ());
+    octave_value::assign_op op = static_cast<octave_value::assign_op> (arg0);
     int n_chained = POP_CODE ();
     std::vector<int> v_n_args;
     std::string type (n_chained, 0);
@@ -5218,11 +5465,16 @@
 
     try
       {
+        if (type.size () && type.back () != '(' && lhs_assign_numel (lhs, type, idx) != 1)
+          err_invalid_structure_assignment ();
+
         lhs.assign (op, type, idx, rhs);
       }
+    CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
+    CATCH_EXIT_EXCEPTION
 
     PUSH_OV (lhs);
   }
@@ -5230,14 +5482,14 @@
 
 set_slot_to_stack_depth:
   {
-    int slot = POP_CODE ();
+    int slot = arg0;
     int stack_depth = sp - bsp;
     bsp[slot].ov = octave_value {stack_depth};
   }
   DISPATCH ();
 dupn:
   {
-    int offset = POP_CODE ();
+    int offset = arg0;
     int n = POP_CODE ();
     stack_element *first = sp - n - offset;
     for (int i = 0; i < n; i++)
@@ -5246,8 +5498,7 @@
   DISPATCH ();
 load_cst_alt2:
   {
-    // The next instruction is the offset in the data.
-    int offset = *ip++;
+    int offset = arg0;
 
     // Copy construct it into the top of the stack
     new (sp++) octave_value (data [offset]);
@@ -5256,8 +5507,7 @@
   }
 load_cst_alt3:
   {
-    // The next instruction is the offset in the data.
-    int offset = *ip++;
+    int offset = arg0;
 
     // Copy construct it into the top of the stack
     new (sp++) octave_value (data [offset]);
@@ -5266,8 +5516,7 @@
   }
 load_cst_alt4:
   {
-    // The next instruction is the offset in the data.
-    int offset = *ip++;
+    int offset = arg0;
 
     // Copy construct it into the top of the stack
     new (sp++) octave_value (data [offset]);
@@ -5279,7 +5528,7 @@
   // We are pushing two constants to the stack. E.g. for "3 * 2".
   // The next instruction is the offset in the data of the lhs.
   // rhs is right after.
-  int offset = *ip++;
+  int offset = arg0;
 
   // Copy construct the two constants onto the top of the stack
   new (sp++) octave_value (data [offset]);     // lhs in a binop
@@ -5288,8 +5537,25 @@
   DISPATCH ();
 }
 /* Check whether we should enter the debugger on the next ip */
-debug_check:
+{
+  bool onebyte_op;
+  if (0)
+    debug_check:
+    onebyte_op = false;
+  else if (0)
+    debug_check_1b:
+    onebyte_op = true;
+  
   {
+    int tmp_ip = ip - code;
+    if (onebyte_op)
+      tmp_ip--;
+
+    if (OCTAVE_UNLIKELY (m_trace_enabled))
+      {
+        PRINT_VM_STATE ("Trace: ");
+      }
+
     if (OCTAVE_UNLIKELY (m_profiler_enabled))
       {
         int64_t t1 = vm_profiler::unow ();
@@ -5301,16 +5567,16 @@
         std::string fn_name = data[2].string_value (); // profiler_name () querried at compile time
         vm_profiler::vm_profiler_fn_stats &stat = p->m_map_fn_stats[fn_name];
 
-        if (!stat.m_v_t0.size ())
+        if (!stat.m_v_t.size ())
           {
             // The profiler got enabled after the current function was called.
             p->enter_fn (fn_name, "", unwind_data, name_data, code);
-            stat.m_v_t0.back () = -1;
+            stat.m_v_t.back () = -1;
             stat.m_v_ip.back () = ip - code; // We are not at function start, so set ip to proper value.
           }
-        else if (stat.m_v_t0.back () != -1)
+        else if (stat.m_v_t.back () != -1)
           {
-            int64_t t0 = stat.m_v_t0.back ();
+            int64_t t0 = stat.m_v_t.back ();
             int64_t dt = t1 - t0;
 
             stat.add_t (dt);
@@ -5322,9 +5588,6 @@
     //       Until another bp is set? Debugging will be quite slow
     //       with one check for each op-code.
 
-    // find() uses int& but we don't want the registers to ever leave the c-stack
-    // so we do a copy here.
-    int tmp_ip = ip - code;
     auto it = unwind_data->m_ip_to_tree.find (tmp_ip);
 
     if (it == unwind_data->m_ip_to_tree.end ())
@@ -5353,40 +5616,54 @@
           {
             m_tw->do_breakpoint (t->is_active_breakpoint (*m_tw), is_ret);
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
         CATCH_BAD_ALLOC
-        catch (interrupt_exception &e)
+        CATCH_EXIT_EXCEPTION
+      }
+  }
+  debug_check_end:
+  {
+    if (OCTAVE_UNLIKELY (m_profiler_enabled))
+      {
+        auto p = m_vm_profiler;
+
+        if (p)
           {
-            (*sp++).i = static_cast<int>(error_type::INTERRUPT_EXC);
-            goto unwind;
+            std::string fn_name = data[2].string_value (); // profiler_name () querried at compile time
+            vm_profiler::vm_profiler_fn_stats &stat = m_vm_profiler->m_map_fn_stats[fn_name];
+
+            // If someone enabled profiling in the debugger we need to wait until
+            // the debug_check: block is ran next time.
+            if (stat.m_v_t.size())
+              {
+                int tmp_ip = ip - code;
+                if (onebyte_op)
+                  tmp_ip--;
+                stat.m_v_ip.back () = tmp_ip; // Sets a new 'currently running ip'
+                stat.m_v_t.back () = vm_profiler::unow (); // Sets a new timestamp for the current ip
+              }
           }
       }
   }
-debug_check_end:
-{
-  if (OCTAVE_UNLIKELY (m_profiler_enabled))
+  if (onebyte_op)
     {
-      auto p = m_vm_profiler;
-
-      if (p)
-        {
-          std::string fn_name = data[2].string_value (); // profiler_name () querried at compile time
-          vm_profiler::vm_profiler_fn_stats &stat = m_vm_profiler->m_map_fn_stats[fn_name];
-
-          // If someone enabled profiling in the debugger we need to wait until
-          // the debug_check: block is ran next time.
-          if (stat.m_v_t0.size())
-            {
-              stat.m_v_ip.back () = ip - code;
-              stat.m_v_t0.back () = vm_profiler::unow ();
-            }
-        }
+      int opcode = ip[-1];
+      arg0 = ip[0];
+      ip++;
+      goto *instr [opcode];
+    }
+  else
+    {
+      int opcode = ip[0];
+      arg0 = ip[1];
+      ip += 2;
+      goto *instr [opcode];
     }
 }
-DISPATCH_NO_DEBUG ();
-
-debug:
+
+debug: // TODO: Remove
   {
     if (m_tw->debug_mode ())
       {
@@ -5398,18 +5675,25 @@
           {
             m_tw->enter_debugger ();
           }
+        CATCH_INTERRUPT_EXCEPTION
         CATCH_INDEX_EXCEPTION
         CATCH_EXECUTION_EXCEPTION
         CATCH_BAD_ALLOC
-        catch (interrupt_exception &e)
-          {
-            (*sp++).i = static_cast<int>(error_type::INTERRUPT_EXC);
-            goto unwind;
-          }
+        CATCH_EXIT_EXCEPTION
       }
   }
   DISPATCH ();
 
+  wide:
+  {
+    int opcode = arg0; // The opcode to execute next is in arg0, i.e. ip[-1]
+    // The next opcode needs its arg0, which is a unsigned short instead of the usual byte
+    // that DISPATCH() writes to arg0.
+    arg0 = (ip[1] << 8) | ip[0];
+    ip += 2; // Forward ip so it points to after the widened argument
+    goto *instr [opcode];
+  }
+
   __builtin_unreachable ();
 }
 
@@ -5443,9 +5727,11 @@
   return symtab.find_function (*name);
 }
 
-void
+vm::error_data
 vm::handle_error (error_type error_type)
 {
+  error_data ret;
+
   error_system& es = m_tw->get_interpreter().get_error_system ();
 
   std::stringstream ss;
@@ -5522,6 +5808,10 @@
       }
     case error_type::INTERRUPT_EXC:
       break; // Do nothing
+    case error_type::EXIT_EXCEPTION:
+      ret.m_safe_to_return = (--m_sp)->i;
+      ret.m_exit_status = (--m_sp)->i;
+      break;
     case error_type::INVALID_N_EL_RHS_IN_ASSIGNMENT:
     {
       execution_exception e {"error", "", "invalid number of elements on RHS of assignment"};
@@ -5542,7 +5832,7 @@
       TODO ("Unhandeled error type");
     }
 
-  return;
+  return ret;
 }
 
 vm::~vm ()
@@ -5570,7 +5860,6 @@
   m_data = initial_bytecode.m_data.data ();
   m_code = initial_bytecode.m_code.data ();
   m_name_data = initial_bytecode.m_ids.data ();
-  m_name_data_size = initial_bytecode.m_ids.size ();
   m_unwind_data = &initial_bytecode.m_unwind_data;
 
   // Check that the typeids are what the VM anticipates. If the id change, just change
@@ -5628,6 +5917,148 @@
     PUSH_OV ();
 }
 
+static octave_value xeval_for_numel (octave_value &ov, const std::string& type, const std::list<octave_value_list>& idx);
+
+// This function reimplements octave_lvalue::numel()
+// TODO: octave_lvalue::numel() could be broken out or made static and used instead. But don't mess with that code 
+//       to keep the VM somewhat independent of other code.
+static int lhs_assign_numel (octave_value &ov, const std::string& type, const std::list<octave_value_list>& idx)
+{
+  // Return 1 if there is no index because without an index there
+  // should be no way to have a cs-list here.  Cs-lists may be passed
+  // around internally but they are not supposed to be stored as
+  // single symbols in a stack frame.
+
+  std::size_t num_indices = idx.size ();
+
+  if (num_indices == 0)
+    return 1;
+
+  switch (type[num_indices-1])
+    {
+    case '(':
+      return 1;
+
+    case '{':
+      {
+        // FIXME: Duplicate code in '.' case below...
+
+        // Evaluate, skipping the last index.
+
+        std::string tmp_type = type;
+        std::list<octave_value_list> tmp_idx = idx;
+
+        tmp_type.pop_back ();
+        tmp_idx.pop_back ();
+
+        octave_value tmp = xeval_for_numel (ov, tmp_type, tmp_idx);
+
+        octave_value_list tidx = idx.back ();
+
+        if (tmp.is_undefined ())
+          {
+            if (tidx.has_magic_colon ())
+              err_invalid_inquiry_subscript ();
+
+            tmp = Cell ();
+          }
+        else if (tmp.is_zero_by_zero ()
+                 && (tmp.is_matrix_type () || tmp.is_string ()))
+          {
+            tmp = Cell ();
+          }
+
+        return tmp.xnumel (tidx);
+      }
+      break;
+
+    case '.':
+      {
+        // Evaluate, skipping either the last index or the last two
+        // indices if we are looking at "(idx).field".
+
+        std::string tmp_type = type;
+        std::list<octave_value_list> tmp_idx = idx;
+
+        tmp_type.pop_back ();
+        tmp_idx.pop_back ();
+
+        bool paren_dot = num_indices > 1 && type[num_indices-2] == '(';
+
+        // Index for paren operator, if any.
+        octave_value_list pidx;
+
+        if (paren_dot)
+          {
+            pidx = tmp_idx.back ();
+
+            tmp_type.pop_back ();
+            tmp_idx.pop_back ();
+          }
+
+        octave_value tmp = xeval_for_numel (ov, tmp_type, tmp_idx);
+
+        bool autoconv = (tmp.is_zero_by_zero ()
+                         && (tmp.is_matrix_type () || tmp.is_string ()
+                             || tmp.iscell ()));
+
+        if (paren_dot)
+          {
+            // Use octave_map, not octave_scalar_map so that the
+            // dimensions are 0x0, not 1x1.
+
+            if (tmp.is_undefined ())
+              {
+                if (pidx.has_magic_colon ())
+                  err_invalid_inquiry_subscript ();
+
+                tmp = octave_map ();
+              }
+            else if (autoconv)
+              tmp = octave_map ();
+
+            return tmp.xnumel (pidx);
+          }
+        else if (tmp.is_undefined () || autoconv)
+          return 1;
+        else
+          return tmp.xnumel (octave_value_list ());
+      }
+      break;
+
+    default:
+      panic_impossible ();
+    }
+}
+
+static octave_value xeval_for_numel (octave_value &ov, const std::string& type, const std::list<octave_value_list>& idx)
+{
+  octave_value retval;
+
+  try
+    {
+      retval = ov;
+
+      if (retval.is_constant () && ! idx.empty ())
+        retval = retval.subsref (type, idx);
+    }
+  catch (const execution_exception&)
+    {
+      // Ignore an error and treat it as undefined.  The error
+      // could happen because there is an index is out of range
+      // and we will be resizing a cell array.
+
+      interpreter& interp = __get_interpreter__ ();
+
+      interp.recover_from_exception ();
+
+      retval = octave_value ();
+    }
+
+  return retval;
+}
+
+
 loc_entry vm::find_loc (int ip, std::vector<octave::loc_entry> &loc_entries)
 {
   int best = -1;
@@ -5707,7 +6138,7 @@
 }
 
 unwind_entry*
-vm::find_unwind_entry_for_current_state ()
+vm::find_unwind_entry_for_current_state (bool only_find_unwind_protect)
 {
   int best_match = -1;
 
@@ -5718,6 +6149,10 @@
       int start = entry.m_ip_start;
       int end = entry.m_ip_end;
 
+      // When unwinding for e.g. interrupt exceptions we are only looking for UNWIND_PROTECT
+      if (only_find_unwind_protect && (entry.m_unwind_entry_type != unwind_entry_type::UNWIND_PROTECT))
+        continue;
+
       // Skip for loop entries
       if (entry.m_unwind_entry_type == unwind_entry_type::FOR_LOOP)
         continue;
@@ -5759,11 +6194,7 @@
 vm_profiler::vm_profiler_fn_stats::add_t (int64_t dt)
 {
   int ip = m_v_ip.back ();
-
-  if (m_v_cum_t.size () <= static_cast<std::size_t> (ip))
-    m_v_cum_t.resize (ip + 1);
-  if (m_v_n_cum.size () <= static_cast<std::size_t> (ip))
-    m_v_n_cum.resize (ip + 1);
+  maybe_resize (ip);
 
   m_v_cum_t[ip] += dt;
   ++m_v_n_cum[ip];
@@ -5775,7 +6206,7 @@
   if (!m_shadow_call_stack.size ())
     return;
 
-  m_shadow_call_stack.back ().m_t_cum += dt;
+  m_shadow_call_stack.back ().m_t_self_cum += dt;
 }
 
 // There is no std::format since we use C++ 11 so lets make our own.
@@ -5832,6 +6263,7 @@
   // These could probably be vectors, but we'll do with maps to keep the
   // code easier to follow.
   map<string, int64_t> map_fn_to_cum_t;
+  map<string, int64_t> map_fn_to_self_cum_t;
   map<string, vector<string>> map_fn_to_sourcerows;
   map<string, vector<pair<int, string>>> map_fn_to_opcodes_stringrows;
   map<string, string> map_fn_to_annotated_source;
@@ -5844,12 +6276,19 @@
       vm_profiler_fn_stats &stats = kv.second;
 
       int64_t t_fn_cum = 0;
+      int64_t t_fn_self_cum = 0;
       unsigned n = stats.m_v_cum_t.size ();
 
       for (unsigned ip = 0; ip < n; ip++)
-        t_fn_cum += stats.m_v_cum_t[ip];
+        {
+          t_fn_cum += stats.m_v_cum_t[ip];
+          t_fn_self_cum += stats.m_v_cum_t[ip];
+        }
+      for (unsigned ip = 0; ip < stats.m_v_cum_call_t.size (); ip++)
+        t_fn_cum += stats.m_v_cum_call_t[ip];
 
       map_fn_to_cum_t[fn_name] = t_fn_cum;
+      map_fn_to_self_cum_t[fn_name] = t_fn_self_cum;
     }
 
   // Try to get the source code
@@ -5953,17 +6392,17 @@
           string s = ls.second; // Text representation of the opcode
 
           // Ignore strange data
-          if (ip < 0 || static_cast<unsigned> (ip) >= stats.m_v_cum_t.size ())
+          if (ip < 0)
             continue;
 
-          if (stats.m_v_cum_t[ip] == 0)
+          if (static_cast<unsigned> (ip) >= stats.m_v_cum_t.size () || (stats.m_v_cum_t[ip] == 0 && stats.m_v_cum_call_t[ip] == 0))
           {
             ans += x_snprintf ("\t%*s %5d: %s\n", 43, "", ip, s.c_str ());
             continue;
           }
 
           int64_t n_hits = stats.m_v_n_cum[ip];
-          int64_t t_op = stats.m_v_cum_t[ip];
+          int64_t t_op = stats.m_v_cum_t[ip] + stats.m_v_cum_call_t[ip];
           double share_of_fn = 100. * static_cast<double> (t_op) / fn_cum_t;
 
           // Try to make the table neat around the decimal separator
@@ -6005,7 +6444,7 @@
 
       for (unsigned ip = 0; ip < stats.m_v_cum_t.size (); ip++)
         {
-          int64_t tcum = stats.m_v_cum_t[ip];
+          int64_t tcum = stats.m_v_cum_t[ip] + stats.m_v_cum_call_t[ip];
           int64_t nhits = stats.m_v_n_cum[ip];
           int src_line = map_op_offset_to_src_line[ip];
           map_srcline_to_tcum[src_line] += tcum;
@@ -6099,6 +6538,7 @@
       vm_profiler_fn_stats &stats = kv.second;
 
       int64_t fn_cum_t = map_fn_to_cum_t[fn_name];
+      int64_t fn_self_cum_t = map_fn_to_self_cum_t[fn_name];
       string annotated_source = map_fn_to_annotated_source[fn_name];
       string annotated_bytecode = map_fn_to_annotated_bytecode[fn_name];
 
@@ -6110,7 +6550,9 @@
       for (string caller : stats.m_set_callers)
         printf ("%s ", caller.c_str ());
       printf ("\n");
-      printf ("\tCumulative time: %9.5gs %lld ns\n\n", fn_cum_t/1e9, static_cast<long long> (fn_cum_t));
+      printf ("\tCumulative time: %9.5gs %lld ns\n", fn_cum_t/1e9, static_cast<long long> (fn_cum_t));
+      printf ("\tCumulative self time: %9.5gs %lld ns\n", fn_self_cum_t/1e9, static_cast<long long> (fn_self_cum_t));
+      printf ("\n\n");
 
       if (annotated_source.size ())
       {
@@ -6163,7 +6605,7 @@
 
   m_shadow_call_stack.push_back (call);
 
-  callee_stat.m_v_t0.push_back (now);
+  callee_stat.m_v_t.push_back (now);
   callee_stat.m_v_ip.push_back (0);
 
   if (callee_stat.m_code.size ())
@@ -6198,7 +6640,7 @@
   {
     auto &v = kv.second;
     v.m_v_callers.clear ();
-    v.m_v_t0.clear ();
+    v.m_v_t.clear ();
     v.m_v_ip.clear ();
   }
 }
@@ -6207,12 +6649,34 @@
 vm_profiler::exit_fn (std::string fn_name)
 {
   {
+    int64_t t_exit = unow ();
+
     vm_profiler_fn_stats &callee_stat = m_map_fn_stats[fn_name];
 
+    // Add the cost of the RET up till now to the callee
+    if (callee_stat.m_v_t.size () && callee_stat.m_v_t.back () != -1)
+      {
+        int64_t t0 = callee_stat.m_v_t.back ();
+        int64_t dt = t_exit - t0;
+
+        callee_stat.add_t (dt);
+        this->add_t (dt);
+      }
+
     if (!m_shadow_call_stack.size ())
       goto error;
     if (!callee_stat.m_v_callers.size ())
       goto error;
+
+    bool is_recursive = false;
+    for (auto &call : m_shadow_call_stack)
+      {
+        if (call.m_caller == fn_name)
+          {
+            is_recursive = true;
+            break;
+          }
+      }
     
     vm_profiler_call call = m_shadow_call_stack.back ();
     m_shadow_call_stack.pop_back ();
@@ -6220,7 +6684,11 @@
     std::string caller = call.m_caller;
 
     std::string caller_according_to_callee = callee_stat.m_v_callers.back ();
+
+    // Pop one level
     callee_stat.m_v_callers.pop_back ();
+    callee_stat.m_v_t.pop_back ();
+    callee_stat.m_v_ip.pop_back ();
 
     if (caller_according_to_callee != caller)
       goto error;
@@ -6229,16 +6697,29 @@
       {
         vm_profiler_fn_stats &caller_stat = m_map_fn_stats[caller];
 
-        if (!caller_stat.m_v_t0.size ())
+        if (!caller_stat.m_v_t.size ())
           goto error;
 
-        int64_t caller_enters_call = caller_stat.m_v_t0.back ();
+        int64_t caller_enters_call = caller_stat.m_v_t.back ();
         int64_t caller_enters_callee = call.m_entry_time;
         int64_t caller_call_overhead = caller_enters_callee - caller_enters_call;
-        int64_t callee_exit = unow ();
-        // Change the caller's last timestamp to now and subtract the accumalted time in the callee and
-        // the caller's call overhead
-        caller_stat.m_v_t0.back () = callee_exit - call.m_t_cum - caller_call_overhead;
+        int64_t callee_dt = call.m_t_self_cum + call.m_t_call_cum - caller_call_overhead;
+
+        // Add the call's cumulative time to the caller's "time spent in bytecode call"-vector
+        // unless the call is recursive (to prevent confusing double book keeping of the time).
+        unsigned caller_ip = caller_stat.m_v_ip.back ();
+        caller_stat.maybe_resize (caller_ip);
+
+        if (!is_recursive)
+        {
+          // Add to cumulative spent in call from this ip, in caller
+          caller_stat.m_v_cum_call_t[caller_ip] += callee_dt;
+          // Add to cumulative time spent in *the latest call* to caller
+          if (m_shadow_call_stack.size ())
+            m_shadow_call_stack.back ().m_t_call_cum += callee_dt;
+        }
+        // Change the caller's last timestamp to now and subtract the caller's call overhead.
+        caller_stat.m_v_t.back () = unow () - caller_call_overhead;
       }
     return;
   }
--- a/libinterp/parse-tree/pt-bytecode-vm.h	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-vm.h	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 2001-2022 The Octave Project Developers
+// Copyright (C) 2022-2023 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -381,34 +381,47 @@
     std::string m_caller;
     std::string m_callee;
     int64_t m_entry_time;
-    int64_t m_t_cum;
+    int64_t m_t_self_cum; // Time spent in callee it-self
+    int64_t m_t_call_cum; // Time spent in bytecode calls, called from callee
   };
 
   struct vm_profiler_fn_stats
   {
     // Cumulative ns time at op-code at offset
     std::vector<int64_t> m_v_cum_t;
-    // Cumulative his at op-code at offset
+    // Cumulative hits at op-code at offset
     std::vector<int64_t> m_v_n_cum;
-    // The start of op-code timestamp. One level per recursive call
-    std::vector<int64_t> m_v_t0;
-    // The ip of the t0 timestamp. One level per recursive call
+    // Cumulative time spent in nested calls to a bytecode function at op-code at offset
+    std::vector<int64_t> m_v_cum_call_t;
+
+    void maybe_resize (unsigned ip)
+    {
+      if (ip >= m_v_cum_t.size ())
+        m_v_cum_t.resize (ip + 1);
+      if (ip >= m_v_n_cum.size ())
+        m_v_n_cum.resize (ip + 1);
+      if (ip >= m_v_cum_call_t.size ())
+        m_v_cum_call_t.resize (ip + 1);
+    }
+
+    // The last bytecode timestamp, i.e. the start of the currently running opcode. One level per call
+    std::vector<int64_t> m_v_t;
+    // The last ip, i.e. the ip being executed. One level per call
     std::vector<int> m_v_ip;
-    // One entry for each caller
+    // Set of callers. One entry for each caller
     std::set<std::string> m_set_callers;
+    // Amount of calls to this function
     int64_t m_n_calls;
 
-    // Data structures to keep track of calls
-    std::vector<std::string> m_v_callers; // Used in callee
+    // Data structures to keep track of calls. One level per call
+    std::vector<std::string> m_v_callers; // Used in callee to change the last timestamp of caller
 
     std::string m_fn_name;
     std::string m_fn_file;
     std::vector<unsigned char> m_code; // Copy of the actual opcodes executed
-    std::vector<std::string> m_ids; // Copy of the name date
+    std::vector<std::string> m_ids; // Copy of the name data
     std::vector<loc_entry> m_loc_entries; // Copy of source code location data
 
-    int64_t m_cum_t;
-
     void add_t (int64_t dt);
   };
 
@@ -442,6 +455,8 @@
   ~vm ();
 
   bool m_dbg_proper_return = false;
+  bool m_could_not_push_frame = false;
+  bool m_unwinding_interrupt = false;
   stack_element *m_stack0 = nullptr;
 
   std::vector<std::shared_ptr<stack_frame>> m_frame_ptr_cache;
@@ -506,11 +521,18 @@
   octave_value *m_data;
   std::string *m_name_data;
   unwind_data *m_unwind_data;
-  unsigned m_name_data_size;
 
   int m_ip;
 
-  void
+  // Generic data container to recreate exceptions
+  struct error_data
+  {
+    // Execution exception
+    int m_exit_status;
+    bool m_safe_to_return;
+  };
+
+  error_data
   handle_error (error_type et);
 
   static 
@@ -526,11 +548,12 @@
 
   void set_nargout (int nargout);
 
-  unwind_entry* find_unwind_entry_for_current_state ();
+  unwind_entry* find_unwind_entry_for_current_state (bool only_find_unwind_protect);
   int find_unwind_entry_for_forloop (int current_stack_depth);
 
   static std::shared_ptr<vm_profiler> m_vm_profiler;
   static bool m_profiler_enabled;
+  static bool m_trace_enabled;
 };
 
 OCTINTERP_API
--- a/libinterp/parse-tree/pt-bytecode-walk.cc	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-walk.cc	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 2017-2022 The Octave Project Developers
+// Copyright (C) 2022-2023 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -99,6 +99,92 @@
   }
 };
 
+class is_foldable_walker : tree_walker
+{
+public:
+  static bool is_foldable (tree_binary_expression &e)
+  {
+    return is_foldable_internal (e);
+  }
+
+  static bool is_foldable (tree_prefix_expression &e)
+  {
+    return is_foldable_internal (e);
+  }
+
+  static bool is_foldable (tree_postfix_expression &e)
+  {
+    return is_foldable_internal (e);
+  }
+
+private:
+  static bool is_foldable_internal (tree &e)
+  {
+    is_foldable_walker walker;
+
+    e.accept (walker);
+
+    return walker.m_is_foldable;
+  }
+
+  bool is_foldable_expr (tree_expression *e)
+  {
+    return e->is_binary_expression () || e->is_unary_expression () || e->is_constant ();
+  }
+
+  void visit_postfix_expression (tree_postfix_expression& e)
+  {
+    if (!m_is_foldable)
+      return;
+
+    tree_expression *op = e.operand ();
+
+    if (!is_foldable_expr (op))
+      {
+        m_is_foldable = false;
+        return;
+      }
+
+    op->accept (*this);
+  }   
+
+  void visit_prefix_expression (tree_prefix_expression& e)
+  {
+    if (!m_is_foldable)
+      return;
+
+    tree_expression *op = e.operand ();
+
+    if (!is_foldable_expr (op))
+      {
+        m_is_foldable = false;
+        return;
+      }
+
+    op->accept (*this);
+  }
+
+  void visit_binary_expression (tree_binary_expression &e)
+  {
+    if (!m_is_foldable)
+      return;
+
+    tree_expression *rhs = e.rhs ();
+    tree_expression *lhs = e.lhs ();
+    if (!is_foldable_expr (rhs) || !is_foldable_expr (lhs))
+      {
+        m_is_foldable = false;
+        return;
+      }
+
+    lhs->accept (*this);
+    if (m_is_foldable)
+      rhs->accept (*this);
+  }
+
+  bool m_is_foldable = true;
+};
+
 class collect_idnames_walker : tree_walker
 {
 public:
@@ -160,26 +246,49 @@
   } while ((0))
 
 #define PUSH_CODE(code_) do {\
-    unsigned char code_s_ = static_cast<unsigned char> (code_);     \
     int code_check_s_ = static_cast<int> (code_); \
+    unsigned char code_s_ = static_cast<unsigned char> (code_check_s_);     \
     CHECK (code_check_s_ < 256 && code_check_s_ >= -128); \
     m_code.m_code.push_back(code_s_);        \
   } while ((0))
 
 #define PUSH_CODE_LOAD_CST(offset) do {\
-  if ((offset) < 256)\
+  unsigned offset_ = offset; \
+  if (offset_ < 65536)\
     {\
+      if (offset_ >= 256) \
+        PUSH_CODE (INSTR::WIDE); \
       emit_alt (m_cnt_alts_cst, {INSTR::LOAD_CST, INSTR::LOAD_CST_ALT2, \
         INSTR::LOAD_CST_ALT3, INSTR::LOAD_CST_ALT4});\
-      PUSH_CODE (offset);\
+      if (offset_ >= 256) \
+        PUSH_CODE_SHORT (offset_);\
+      else\
+        PUSH_CODE (offset_);\
     }\
   else\
     {\
       PUSH_CODE (INSTR::LOAD_FAR_CST);\
-      PUSH_CODE_INT (offset);\
+      PUSH_CODE_INT (offset_);\
     }\
 } while (0)
 
+#define PUSH_SSLOT(sslot) PUSH_CODE(sslot)
+#define PUSH_WSLOT(wslot) PUSH_CODE_SHORT(wslot)
+#define NEED_WIDE_SLOTS() (m_map_locals_to_slot.size () >= 256)
+
+#define MAYBE_PUSH_WIDE_OPEXT(slot) \
+do {\
+  if (slot >= 256)\
+    PUSH_CODE (INSTR::WIDE);\
+} while ((0))
+
+#define PUSH_SLOT(slot) \
+do {\
+  if (slot >= 256)\
+    PUSH_WSLOT (slot);\
+  else\
+    PUSH_SSLOT (slot);\
+} while ((0))
 
 #define CODE_SIZE() m_code.m_code.size()
 #define CODE(x) m_code.m_code[x]
@@ -187,6 +296,8 @@
   unsigned u = code_;                 \
   unsigned char b0 = u & 0xFF;        \
   unsigned char b1 = (u >> 8) & 0xFF; \
+  int code_check_ss_ = static_cast<int> (u);                  \
+  CHECK (code_check_ss_ < 65536 && code_check_ss_ >= -32768); \
   PUSH_CODE (b0);                     \
   PUSH_CODE (b1);                     \
   } while ((0))
@@ -207,6 +318,8 @@
   unsigned u = value;                       \
   unsigned char b0 = u & 0xFF;              \
   unsigned char b1 = (u >> 8) & 0xFF;       \
+  int code_check_s_ = static_cast<int> (u); \
+  CHECK (code_check_s_ < 65536 && code_check_s_ >= -32768); \
   CODE (tmp) = b0;                          \
   CODE (tmp + 1) = b1;                      \
   } while ((0))
@@ -995,9 +1108,10 @@
     {
       // ... so assign it to the identifiers in its slot.
       std::string name = expr_id->name ();
-      add_id_to_table (name);
+      int slot = add_id_to_table (name);
+      MAYBE_PUSH_WIDE_OPEXT (slot);
       PUSH_CODE (INSTR::ASSIGN);
-      PUSH_CODE (SLOT (name));
+      PUSH_SLOT (slot);
     }
   else
     {
@@ -1061,7 +1175,7 @@
 
       std::string name = el->name ();
 
-      add_id_to_table (name);
+      int slot = add_id_to_table (name);
 
       if (el->is_global () || el->is_persistent())
         {
@@ -1088,7 +1202,7 @@
           else
             prefix = "+";
 
-          add_id_to_table (prefix + name);
+          int prefix_slot = add_id_to_table (prefix + name);
 
           PUSH_CODE (INSTR::GLOBAL_INIT);
           if (el->is_global ())
@@ -1107,10 +1221,10 @@
               // The VM need to know the special persistent variable offset
               // so we store it in the unwind data
               m_code.m_unwind_data.
-                m_slot_to_persistent_slot[SLOT (name)] = offset;
+                m_slot_to_persistent_slot[slot] = offset;
             }
-          PUSH_CODE (SLOT (name));
-          PUSH_CODE (SLOT (prefix + name));
+          PUSH_WSLOT (slot);
+          PUSH_WSLOT (prefix_slot);
 
           tree_expression *expr = el->expression ();
           bool has_init = expr;
@@ -1137,8 +1251,9 @@
               // The value of rhs is on the operand stack now.
               // So we need to write it to its local slot and then
               // write that to its global value.
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::ASSIGN); // Write operand stack top ...
-              PUSH_CODE (SLOT (name));   // to the local slot of the global
+              PUSH_SLOT (slot);   // to the local slot of the global
 
               // I think only this makes sense
               CHECK (DEPTH () == 1);
@@ -1166,6 +1281,26 @@
 
   octave_value::unary_op op = expr.op_type ();
 
+  int folded_need_after = -1;
+  int fold_slot = -1;
+  // Check if we should to a constant fold. It only makes sense in loops since the expression is folded at runtime.
+  // Essentially there is a PUSH_FOLDED_CST opcode that is tied to a cache. If the cache is valid, push it and jump
+  // past the initialization code, otherwise run the initialization code and set the cache with SET_FOLDED_CST
+  if (m_n_nested_loops && !m_is_folding && is_foldable_walker::is_foldable (expr))
+    {
+      m_is_folding = true;
+
+      std::string fold_name = "#cst_fold_" + std::to_string (m_n_folds++);
+      fold_slot = add_id_to_table (fold_name);
+
+      MAYBE_PUSH_WIDE_OPEXT (fold_slot);
+      PUSH_CODE (INSTR::PUSH_FOLDED_CST);
+      PUSH_SLOT (fold_slot);
+      folded_need_after = CODE_SIZE ();
+      PUSH_CODE_SHORT (-1);
+    }
+
+  int slot = -1;
   // For ++ and -- we don't want a local pushed to the stack, but operate
   // directly in the slot, and then pushing the slot.
   if (e->is_identifier() && (op == octave_value::unary_op::op_decr ||
@@ -1174,7 +1309,7 @@
       // Just add the symbol to the table
       // TODO: Could there be command function calls messing this up?
       //       I.e. foo++ could be a foo()++?
-      add_id_to_table (e->name ());
+      slot = add_id_to_table (e->name ());
     }
   // We handle e.g. m("qwe")++ with eval
   else if (op != octave_value::unary_op::op_incr && op != octave_value::unary_op::op_decr)
@@ -1215,10 +1350,9 @@
           }
         else
           {
-            std::string name = e->name ();
-
+            MAYBE_PUSH_WIDE_OPEXT (slot);
             PUSH_CODE (INSTR::INCR_ID_POSTFIX);
-            PUSH_CODE (SLOT (name));
+            PUSH_SLOT (slot);
           }
       }
       break;
@@ -1236,10 +1370,9 @@
           }
         else
           {
-            std::string name = e->name ();
-
+            MAYBE_PUSH_WIDE_OPEXT (slot);
             PUSH_CODE (INSTR::DECR_ID_POSTFIX);
-            PUSH_CODE (SLOT (name));
+            PUSH_SLOT (slot);
           }
       }
       break;
@@ -1247,6 +1380,18 @@
       TODO ("not covered");
     }
 
+  if (fold_slot != -1)
+    {
+      m_is_folding = false;
+
+      PUSH_CODE (INSTR::DUP);
+      MAYBE_PUSH_WIDE_OPEXT (fold_slot);
+      PUSH_CODE (INSTR::SET_FOLDED_CST);
+      PUSH_SLOT (fold_slot);
+
+      SET_CODE_SHORT (folded_need_after, CODE_SIZE ());
+    }
+
   maybe_emit_bind_ans_and_disp (expr);
 
   DEC_DEPTH();
@@ -1263,6 +1408,26 @@
 
   octave_value::unary_op op = expr.op_type ();
 
+  int folded_need_after = -1;
+  int fold_slot = -1;
+  // Check if we should to a constant fold. It only makes sense in loops since the expression is folded at runtime.
+  // Essentially there is a PUSH_FOLDED_CST opcode that is tied to a cache. If the cache is valid, push it and jump
+  // past the initialization code, otherwise run the initialization code and set the cache with SET_FOLDED_CST
+  if (m_n_nested_loops && !m_is_folding && is_foldable_walker::is_foldable (expr))
+    {
+      m_is_folding = true;
+
+      std::string fold_name = "#cst_fold_" + std::to_string (m_n_folds++);
+      fold_slot = add_id_to_table (fold_name);
+
+      MAYBE_PUSH_WIDE_OPEXT (fold_slot);
+      PUSH_CODE (INSTR::PUSH_FOLDED_CST);
+      PUSH_SLOT (fold_slot);
+      folded_need_after = CODE_SIZE ();
+      PUSH_CODE_SHORT (-1);
+    }
+
+  int slot = -1;
   // For ++ and -- we don't want a local pushed to the stack, but operate
   // directly in the slot, and then pushing the slot.
   if (e->is_identifier() && (op == octave_value::unary_op::op_decr ||
@@ -1271,7 +1436,7 @@
       // Just add the symbol to the table
       // TODO: Could there be command function calls messing this up?
       //       I.e. foo++ could be a foo()++?
-      add_id_to_table (e->name ());
+      slot = add_id_to_table (e->name ());
     }
   // We handle e.g. m("qwe")++ with eval
   else if (op != octave_value::unary_op::op_incr && op != octave_value::unary_op::op_decr)
@@ -1312,10 +1477,9 @@
           }
         else
           {
-            std::string name = e->name ();
-
+            MAYBE_PUSH_WIDE_OPEXT (slot);
             PUSH_CODE (INSTR::INCR_ID_PREFIX);
-            PUSH_CODE (SLOT (name));
+            PUSH_SLOT (slot);
           }
       }
       break;
@@ -1333,9 +1497,9 @@
           }
         else
           {
-            std::string name = e->name ();
+            MAYBE_PUSH_WIDE_OPEXT (slot);
             PUSH_CODE (INSTR::DECR_ID_PREFIX);
-            PUSH_CODE (SLOT (name));
+            PUSH_SLOT (slot);
           }
       }
       break;
@@ -1343,6 +1507,18 @@
       TODO ("not covered");
     }
 
+  if (fold_slot != -1)
+    {
+      m_is_folding = false;
+
+      PUSH_CODE (INSTR::DUP);
+      MAYBE_PUSH_WIDE_OPEXT (fold_slot);
+      PUSH_CODE (INSTR::SET_FOLDED_CST);
+      PUSH_SLOT (fold_slot);
+
+      SET_CODE_SHORT (folded_need_after, CODE_SIZE ());
+    }
+
   maybe_emit_bind_ans_and_disp (expr);
 
   DEC_DEPTH();
@@ -1511,6 +1687,7 @@
   PUSH_NARGOUT (1);
 
   std::vector<int> need_after;
+  int fold_slot = -1;
 
   // "&" and "|" have a braindead short circuit behavoiur when
   // in if or while conditions, so we need special handling of those.
@@ -1522,7 +1699,7 @@
           // or not
           std::string id_warning = "%braindead_warning_" +
             std::to_string(CODE_SIZE ());
-          add_id_to_table(id_warning);
+          int slot = add_id_to_table(id_warning);
 
           // The left most expression is always evaled
           tree_expression *op1 = expr.lhs ();
@@ -1551,8 +1728,9 @@
 
           // The lhs was false which means we need to issue a warning
           // and push a false
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::BRAINDEAD_WARNING);
-          PUSH_CODE (SLOT (id_warning));
+          PUSH_SLOT (slot);
           PUSH_CODE ('&'); // The operand type to print in the warning
           PUSH_CODE (INSTR::PUSH_FALSE);
           PUSH_CODE (INSTR::JMP);
@@ -1597,7 +1775,7 @@
           // or not
           std::string id_warning = "%braindead_warning_" +
             std::to_string(CODE_SIZE ());
-          add_id_to_table(id_warning);
+          int slot = add_id_to_table(id_warning);
 
           // The left most expression is always evaled
           tree_expression *op1 = expr.lhs ();
@@ -1626,8 +1804,9 @@
           int need_target_check_rhs = CODE_SIZE ();
           PUSH_CODE_SHORT (-1);
 
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::BRAINDEAD_WARNING);
-          PUSH_CODE (SLOT (id_warning));
+          PUSH_SLOT (slot);
           PUSH_CODE ('|'); // The operand type to print in the warning
           PUSH_CODE (INSTR::PUSH_TRUE);
           PUSH_CODE (INSTR::JMP);
@@ -1669,15 +1848,32 @@
       else
         panic_impossible ();
     }
+  // Check if we should to a constant fold. It only makes sense in loops since the expression is folded at runtime.
+  // Essentially there is a PUSH_FOLDED_CST opcode that is tied to a cache. If the cache is valid, push it and jump
+  // past the initialization code, otherwise run the initialization code and set the cache with SET_FOLDED_CST
+  else if (m_n_nested_loops && !m_is_folding && is_foldable_walker::is_foldable (expr))
+    {
+      m_is_folding = true;
+
+      std::string fold_name = "#cst_fold_" + std::to_string (m_n_folds++);
+      fold_slot = add_id_to_table (fold_name);
+
+      MAYBE_PUSH_WIDE_OPEXT (fold_slot);
+      PUSH_CODE (INSTR::PUSH_FOLDED_CST);
+      PUSH_SLOT (fold_slot);
+      need_after.push_back (CODE_SIZE ());
+      PUSH_CODE_SHORT (-1);
+    }
 
   tree_expression *op1 = expr.lhs ();
   tree_expression *op2 = expr.rhs ();
   CHECK_NONNULL (op1);
   CHECK_NONNULL (op2);
 
-  if (op1->is_constant () && op2->is_constant ())
+  if (op1->is_constant () && op2->is_constant () && DATA_SIZE () < 255)
     {
       // If both rhs and lhs are constants we want to emit a super op-code
+      // aslong as the WIDE op is not going to be used (<255)
       emit_load_2_cst (op1, op2);
     }
   else
@@ -1747,6 +1943,16 @@
       TODO ("not covered");
     }
 
+  if (fold_slot != -1)
+    {
+      m_is_folding = false;
+
+      PUSH_CODE (INSTR::DUP);
+      MAYBE_PUSH_WIDE_OPEXT (fold_slot);
+      PUSH_CODE (INSTR::SET_FOLDED_CST);
+      PUSH_SLOT (fold_slot);
+    }
+
   for (int offset : need_after)
     SET_CODE_SHORT (offset, CODE_SIZE ());
 
@@ -1780,19 +1986,10 @@
   PUSH_DATA (ov_rhs);
 
   unsigned cst_offset = DATA_SIZE () - 1;
-
-    if (cst_offset < 256)
-    {
-      PUSH_CODE (INSTR::LOAD_2_CST);
-      PUSH_CODE (cst_offset - 1); // Offset of lhs
-    }
-  else
-    {
-      PUSH_CODE (INSTR::LOAD_FAR_CST);
-      PUSH_CODE_INT (cst_offset - 1);
-      PUSH_CODE (INSTR::LOAD_FAR_CST);
-      PUSH_CODE_INT (cst_offset);
-    }
+  CHECK (cst_offset < 256);
+
+  PUSH_CODE (INSTR::LOAD_2_CST);
+  PUSH_CODE (cst_offset - 1); // Offset of lhs
 
   DEC_DEPTH();
 }
@@ -1892,6 +2089,7 @@
   // to it for later
   m_offset_n_locals = CODE_SIZE ();
   PUSH_CODE (-1); // Placeholder
+  PUSH_CODE (-1);
 
   // The first slot is a native int represenation nargout
   // so we add a dummy slot object for it
@@ -1928,17 +2126,21 @@
           // slot.
 
           std::string dummy_name = "!" + name;
-          add_id_to_table (dummy_name);
+          int slot_dummy = add_id_to_table (dummy_name);
 
           // PUSH_SLOT_INDEXED just pushes and does not check
           // for doing a cmd function call.
+          MAYBE_PUSH_WIDE_OPEXT (slot_dummy);
           PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-          PUSH_CODE (SLOT (dummy_name));
+          PUSH_SLOT (slot_dummy);
+          int slot = SLOT (name); 
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::FORCE_ASSIGN); // Accepts undefined rhs
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
           PUSH_CODE (INSTR::PUSH_FALSE); // False will do
+          MAYBE_PUSH_WIDE_OPEXT (slot_dummy);
           PUSH_CODE (INSTR::ASSIGN);
-          PUSH_CODE (SLOT (dummy_name));
+          PUSH_SLOT (slot_dummy);
 
           continue;
         }
@@ -2043,8 +2245,8 @@
             {
               // Add the function name id to the table and add the correct external offset.
               // (The name might not be the call-name of the function.)
-              add_id_to_table (name);
-              m_code.m_unwind_data.m_external_frame_offset_to_internal[offset] = SLOT (name);
+              int slot = add_id_to_table (name);
+              m_code.m_unwind_data.m_external_frame_offset_to_internal[offset] = slot;
             }
           else
             continue;
@@ -2072,10 +2274,12 @@
               // There is a default arg.
 
               std::string name = (*it)->name ();
+              int slot = SLOT (name);
 
               // Push the arg to the operand stack from its slot
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-              PUSH_CODE (SLOT (name));
+              PUSH_SLOT (slot);
               // If it is undefined or "Magic colon", execute the init code
               // otherwise jump past it.
               PUSH_CODE (INSTR::JMP_IFDEF);
@@ -2090,8 +2294,9 @@
 
               // The value of rhs is now on the operand stack. Assign it
               // to the arg.
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::ASSIGN);
-              PUSH_CODE (SLOT (name));
+              PUSH_SLOT (slot);
 
               POP_NARGOUT ();
               DEC_DEPTH();
@@ -2107,7 +2312,7 @@
   cmd_list->accept (*this);
 
   // Set the amount of locals that has a placeholder since earlier
-  m_code.m_code[m_offset_n_locals] = m_n_locals;
+  SET_CODE_SHORT (m_offset_n_locals, m_n_locals);
 
   // We want to add the locals to the scope in slot order
   // so we push all the locals' names to a vector by their slot
@@ -2269,7 +2474,7 @@
 
   // Push the slots
   for (std::string &name : v_arg_names)
-    PUSH_CODE (SLOT (name));
+    PUSH_WSLOT (SLOT (name));
 
   // Emit code to disp if no ;
   for (std::string &name : v_arg_names)
@@ -2288,7 +2493,7 @@
       for (unsigned j = 0; j < n_args; j++)
         {
           if (v_is_blackhole.at (j))
-            PUSH_CODE (SLOT (v_arg_names.at (j)));
+            PUSH_WSLOT (SLOT (v_arg_names.at (j)));
         }
 
       emit_unwind_protect_code_end (D);
@@ -2378,8 +2583,8 @@
   // Magic slot number 0 (%nargout that is a native int) that
   // will never be printed corrensponds to "" name tag stashing of
   // the ovl before calling display.
-  PUSH_CODE (0);
-  PUSH_CODE (0); // never a command function call
+  PUSH_SLOT (0);
+  PUSH_WSLOT (0); // never a command function call
 }
 
 void
@@ -2393,8 +2598,10 @@
     return;
 
   CHECK (DEPTH () == 1);
+  int slot = SLOT (name);
+  MAYBE_PUSH_WIDE_OPEXT (slot);
   PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-  PUSH_CODE (SLOT (name));
+  PUSH_SLOT (slot);
   maybe_emit_disp_id (expr, name, maybe_cmd_name); // Always, not maybe
 }
 
@@ -2417,8 +2624,10 @@
   arg_name_entry.m_ip_start = CODE_SIZE ();
 
   CHECK (DEPTH () == 1);
+  int slot = SLOT (name);
+  MAYBE_PUSH_WIDE_OPEXT (slot);
   PUSH_CODE (INSTR::DISP);
-  PUSH_CODE (SLOT (name));
+  PUSH_SLOT (slot);
   // E.g. "x" might either be a command call x() that should print
   // "ans = ..." or a variable that should print "x = ..." so we
   // store the information on whether a certain symbol
@@ -2426,9 +2635,9 @@
   // Some expressions like "1+1" are never command calls
   // ans have maybe_cmd_name as ""
   if (maybe_cmd_name != "")
-    PUSH_CODE (SLOT (maybe_cmd_name));
+    PUSH_WSLOT (SLOT (maybe_cmd_name));
   else
-    PUSH_CODE (0);
+    PUSH_WSLOT (0);
 
   arg_name_entry.m_ip_end = CODE_SIZE ();
   PUSH_ARGNAMES_ENTRY (arg_name_entry);
@@ -2446,8 +2655,10 @@
     {
       if (print_result)
         PUSH_CODE (INSTR::DUP);
+      int slot = SLOT ("ans");
+      MAYBE_PUSH_WIDE_OPEXT (slot);
       PUSH_CODE (INSTR::BIND_ANS);
-      PUSH_CODE (SLOT ("ans"));
+      PUSH_SLOT (slot);
     }
 
   if (expr.is_identifier ())
@@ -2604,10 +2815,11 @@
           // Name of the identifier
           std::string name = e->name ();
 
-          add_id_to_table (name);
-
+          int slot = add_id_to_table (name);
+
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
         }
       else
         {
@@ -2641,8 +2853,9 @@
           // Write the root value to the slot
           // i.e. root(2:end)(3,end)
           PUSH_CODE (INSTR::DUP);
+          MAYBE_PUSH_WIDE_OPEXT (active_idx_slot);
           PUSH_CODE (INSTR::FORCE_ASSIGN);
-          PUSH_CODE (active_idx_slot);
+          PUSH_SLOT (active_idx_slot);
         }
 
       std::vector<int> n_args_per_part;
@@ -2701,8 +2914,9 @@
           if (idx_has_ends && i + 1 != n_chained)
             {
               // Push the prior active index subexpression
+              MAYBE_PUSH_WIDE_OPEXT (active_idx_slot);
               PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-              PUSH_CODE (active_idx_slot);
+              PUSH_SLOT (active_idx_slot);
               // Duplicate the args
               PUSH_CODE (INSTR::DUPN);
               PUSH_CODE (1); // offset, under the object being indexed
@@ -2711,12 +2925,13 @@
               PUSH_CODE (INSTR::INDEX_OBJ);
               PUSH_CODE (1); // nargout
               PUSH_CODE (0); // "has slot"
-              PUSH_CODE (0); // The w/e slot
+              PUSH_WSLOT (0); // The w/e slot
               PUSH_CODE (n_args_in_part);
               PUSH_CODE (type);
               // Write the new active subexpression back to the slot
+              MAYBE_PUSH_WIDE_OPEXT (active_idx_slot);
               PUSH_CODE (INSTR::FORCE_ASSIGN);
-              PUSH_CODE (active_idx_slot);
+              PUSH_SLOT (active_idx_slot);
             }
 
           n_args_per_part.push_back (n_args_in_part);
@@ -2745,8 +2960,10 @@
             PUSH_CODE (INSTR::DUP);
 
           // Write the subassigned value back to the slot
+          int slot = SLOT (e->name ());
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::FORCE_ASSIGN);
-          PUSH_CODE (SLOT (e->name ()));
+          PUSH_SLOT (slot);
 
           maybe_emit_push_and_disp_id (expr, e->name ());
         }
@@ -2834,11 +3051,11 @@
               if (obj_has_end)
                 {
                   std::string obj_stack_depth_name = "%objsd_" + std::to_string (CODE_SIZE ());
-                  add_id_to_table (obj_stack_depth_name);
-
+                  obj_stack_depth_slot = add_id_to_table (obj_stack_depth_name);
+
+                  MAYBE_PUSH_WIDE_OPEXT (obj_stack_depth_slot);
                   PUSH_CODE (INSTR::SET_SLOT_TO_STACK_DEPTH);
-                  obj_stack_depth_slot = SLOT (obj_stack_depth_name);
-                  PUSH_CODE (obj_stack_depth_slot);
+                  PUSH_SLOT (obj_stack_depth_slot);
                 }
 
               nargs = arg->size ();
@@ -2908,22 +3125,27 @@
           //   Gives: a == 3
           // We use a slot to store the rhs in.
           std::string rhs_copy_nm = "%rhs_" + std::to_string (CODE_SIZE ());
+          int slot_cpy = -1;
           if (DEPTH () != 1)
             {
-              add_id_to_table (rhs_copy_nm);
+              slot_cpy = add_id_to_table (rhs_copy_nm);
               PUSH_CODE (INSTR::DUP);
+              MAYBE_PUSH_WIDE_OPEXT (slot_cpy);
               PUSH_CODE (INSTR::FORCE_ASSIGN);
-              PUSH_CODE (SLOT (rhs_copy_nm));
+              PUSH_SLOT (slot_cpy);
             }
 
+          int slot = SLOT (name);
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::SUBASSIGN_ID);
+          PUSH_SLOT (slot);
           PUSH_CODE (nargs);
-          PUSH_CODE (SLOT (name));
 
           if (DEPTH () != 1)
             {
+              MAYBE_PUSH_WIDE_OPEXT (slot_cpy);
               PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-              PUSH_CODE (SLOT (rhs_copy_nm));
+              PUSH_SLOT (slot_cpy);
             }
 
           maybe_emit_push_and_disp_id (expr, name);
@@ -2948,7 +3170,7 @@
               std::string field_name = pv_nms->elem (0);
 
               // We just need the field's name in the VM
-              add_id_to_table (field_name);
+              int slot_field = add_id_to_table (field_name);
 
               tree_expression *rhs = expr.right_hand_side ();
 
@@ -2957,22 +3179,27 @@
               // The value of rhs is on the operand stack now
 
               std::string rhs_copy_nm = "%rhs_" + std::to_string (CODE_SIZE ());
+              int slot_cpy = -1;
               if (DEPTH () != 1) // Chained assignments?
                 {
-                  add_id_to_table (rhs_copy_nm);
+                  slot_cpy = add_id_to_table (rhs_copy_nm);
                   PUSH_CODE (INSTR::DUP);
+                  MAYBE_PUSH_WIDE_OPEXT (slot_cpy);
                   PUSH_CODE (INSTR::FORCE_ASSIGN);
-                  PUSH_CODE (SLOT (rhs_copy_nm));
+                  PUSH_SLOT (slot_cpy);
                 }
 
+              int slot = SLOT (name);
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::SUBASSIGN_STRUCT);
-              PUSH_CODE (SLOT (name));
-              PUSH_CODE (SLOT (field_name));
+              PUSH_SLOT (slot);
+              PUSH_WSLOT (slot_field);
 
               if (DEPTH () != 1)
                 {
+                  MAYBE_PUSH_WIDE_OPEXT (slot_cpy);
                   PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-                  PUSH_CODE (SLOT (rhs_copy_nm));
+                  PUSH_SLOT (slot_cpy);
                 }
 
               maybe_emit_push_and_disp_id (expr, name);
@@ -2990,8 +3217,10 @@
               // The value of rhs is on the stack now
 
               // We want lhs on the stack
+              int slot = SLOT (name);
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-              PUSH_CODE (SLOT (name));
+              PUSH_SLOT (slot);
 
               // The argument, foo.(arg) = bar
               tree_expression *dyn_expr = dyn_fields.front ();
@@ -3013,8 +3242,9 @@
 
               // Assign the assigned to value back to the slot
               // TODO: Neccessary?
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::FORCE_ASSIGN);
-              PUSH_CODE (SLOT (name));
+              PUSH_SLOT (slot);
 
               maybe_emit_push_and_disp_id (expr, name);
             }
@@ -3137,22 +3367,27 @@
           // Gives: a == 3
           // We use a slot to store the rhs in.
           std::string rhs_copy_nm = "%rhs_" + std::to_string (CODE_SIZE ());
+          int slot_cpy = -1;
           if (DEPTH () != 1)
             {
-              add_id_to_table (rhs_copy_nm);
+              slot_cpy = add_id_to_table (rhs_copy_nm);
               PUSH_CODE (INSTR::DUP);
+              MAYBE_PUSH_WIDE_OPEXT (slot_cpy);
               PUSH_CODE (INSTR::FORCE_ASSIGN);
-              PUSH_CODE (SLOT (rhs_copy_nm));
+              PUSH_SLOT (slot_cpy);
             }
 
+          int slot = SLOT (name);
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::SUBASSIGN_CELL_ID);
+          PUSH_SLOT (slot);
           PUSH_CODE (nargs);
-          PUSH_CODE (SLOT (name));
 
           if (DEPTH () != 1)
             {
+              MAYBE_PUSH_WIDE_OPEXT (slot_cpy);
               PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-              PUSH_CODE (SLOT (rhs_copy_nm));
+              PUSH_SLOT (slot_cpy);
             }
 
           maybe_emit_push_and_disp_id (expr, name);
@@ -3164,7 +3399,7 @@
     {
       std::string name = lhs->name ();
 
-      add_id_to_table (name);
+      int slot = add_id_to_table (name);
 
       tree_expression *rhs = expr.right_hand_side ();
 
@@ -3175,15 +3410,17 @@
       if (op != octave_value::assign_op::op_asn_eq)
         {
           // Compound assignment have the type of operation in the code
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::ASSIGN_COMPOUND);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
           PUSH_CODE (op);
         }
       else
         {
           // Ordinary assignment has its own opcode.
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::ASSIGN);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
         }
 
       // If the assignment is not at root we want to keep the
@@ -3191,8 +3428,9 @@
       // a = (b = 3);
       if (DEPTH () != 1)
         {
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
         }
 
       maybe_emit_push_and_disp_id (expr, name);
@@ -3372,18 +3610,20 @@
           if (obj.type == 0)
             {
               /* TODO: Is this op-code with slots really needed? */
+              MAYBE_PUSH_WIDE_OPEXT (obj.slot);
               PUSH_CODE (INSTR::END_ID);
+              PUSH_SLOT (obj.slot); // The slot variable being indexed
               PUSH_CODE (obj.nargs); // The amount of dimensions being indexed
               PUSH_CODE (obj.idx); // The offset of the index being indexed right now
-              PUSH_CODE (obj.slot); // The slot variable being indexed
             }
           else if (obj.type == 1)
             {
+              MAYBE_PUSH_WIDE_OPEXT (obj.slot);
               PUSH_CODE (INSTR::END_OBJ);
+              // Slot for keeping the stack depth of the object being indexed
+              PUSH_SLOT (obj.slot);
               PUSH_CODE (obj.nargs); // The amount of dimensions being indexed
               PUSH_CODE (obj.idx); // The offset of the index being indexed right now
-              // Slot for keeping the stack depth of the object being indexed
-              PUSH_CODE (obj.slot);
             }
           else
             panic_impossible ();
@@ -3401,13 +3641,13 @@
               PUSH_CODE (obj.nargs);
               PUSH_CODE (obj.idx);
               PUSH_CODE (obj.type);
-              PUSH_CODE (obj.slot);
+              PUSH_WSLOT (obj.slot);
             }
         }
     }
   else
     {
-      add_id_to_table (name);
+      int slot = add_id_to_table (name);
 
       int loc_id = N_LOC ();
       PUSH_LOC ();
@@ -3427,11 +3667,12 @@
           // "foo.a" and "foo{1}" might be command function calls
           // which is checked for in PUSH_SLOT_NARGOUT1_SPECIAL
           // Also foo might be a classdef meta object.
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           if (id.postfix_index () != '(')
             PUSH_CODE (INSTR::PUSH_SLOT_NARGOUT1_SPECIAL);
           else
             PUSH_CODE (INSTR::PUSH_SLOT_INDEXED);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
         }
       else if (DEPTH () == 1)
         {
@@ -3443,17 +3684,19 @@
               // or not for display since "x" will print "x = 3"
               // for e.g. variables but "ans = 3" for command calls.
               std::string maybe_cmd_name = "%maybe_command";
-              add_id_to_table (maybe_cmd_name);
+              int slot_cmd = add_id_to_table (maybe_cmd_name);
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::PUSH_SLOT_DISP);
-              PUSH_CODE (SLOT (name));
-              PUSH_CODE (SLOT (maybe_cmd_name));
+              PUSH_SLOT (slot);
+              PUSH_WSLOT (slot_cmd);
 
               maybe_emit_bind_ans_and_disp (id, maybe_cmd_name);
             }
           else
             {
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::PUSH_SLOT_NARGOUT0);
-              PUSH_CODE (SLOT (name));
+              PUSH_SLOT (slot);
 
               // Write the return value to ans. It is either the variables
               // value straight off, or e.g. a cmd function call return value.
@@ -3463,23 +3706,26 @@
       else if (NARGOUT () == 1)
         {
           // Push the local at its slot number to the stack
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           if (name == "pi")
             PUSH_CODE (INSTR::PUSH_PI);
           else
             PUSH_CODE (INSTR::PUSH_SLOT_NARGOUT1);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
         }
       else if (NARGOUT() > 1)
         {
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::PUSH_SLOT_NARGOUTN);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
           PUSH_CODE (NARGOUT ());
         }
       else
         {
           // Push the local at its slot number to the stack
+          MAYBE_PUSH_WIDE_OPEXT (slot);
           PUSH_CODE (INSTR::PUSH_SLOT_NARGOUT0);
-          PUSH_CODE (SLOT (name));
+          PUSH_SLOT (slot);
         }
 
       LOC (loc_id).m_ip_end = CODE_SIZE ();
@@ -3489,7 +3735,7 @@
   DEC_DEPTH();
 }
 
-void
+int
 bytecode_walker::
 add_id_to_table (std::string name)
 {
@@ -3501,7 +3747,11 @@
       // Push local
       m_code.m_ids.push_back(name);
       m_map_locals_to_slot[name] = m_n_locals++;
+
+      return m_n_locals - 1;
     }
+  
+  return it->second;
 }
 
 void
@@ -3542,8 +3792,10 @@
   PUSH_CODE (INSTR::HANDLE_SIGNALS);
 
   // A empty body will yield a null list pointer
+  m_n_nested_loops++;
   if (list)
     list->accept (*this);
+  m_n_nested_loops--;
 
   // Any continue jumps to here (before the condition)
   for (int offset : POP_CONTINUE_TARGET())
@@ -3603,8 +3855,10 @@
   PUSH_CODE (INSTR::HANDLE_SIGNALS);
 
   // nullptr if body is empty
+  m_n_nested_loops++;
   if (list)
     list->accept (*this);
+  m_n_nested_loops--;
 
   // The continue targets can now be set, to jump back
   // to the condition.
@@ -3847,67 +4101,6 @@
     SET_CODE_SHORT (offset, CODE_SIZE ());
 }
 
-#if 0
-void
-bytecode_walker::
-visit_simple_index_expression (tree_simple_index_expression& expr)
-{
-  INC_DEPTH ();
-  tree_expression *e = expr.expression ();
-  CHECK_NONNULL(e);
-
-  if (! e->is_identifier ())
-    TODO ("non id:s need a special opcode to not have a name opcode");
-  std::string id_name = e->name ();
-
-  // Should push the object to index to the stack
-  INC_DEPTH ();
-  e->accept (*this);
-  DEC_DEPTH ();
-
-  tree_argument_list *arg = expr.arg ();
-
-  if (arg)
-    {
-      int nargs = arg->size ();
-      int idx = 0;
-      // We want to push the args to the stack
-      for (auto it = arg->begin (); it != arg->end (); it++, idx++)
-        {
-          INC_DEPTH ();
-          PUSH_ID_BEGIN_INDEXED (SLOT (id_name), idx, nargs);
-          (*it)->accept (*this);
-          POP_ID_BEING_INDEXED ();
-          DEC_DEPTH ();
-        }
-    }
-
-  int loc_id = N_LOC ();
-  PUSH_LOC ();
-  LOC (loc_id).m_ip_start = CODE_SIZE ();
-
-  if (NARGOUT () == 0)
-    PUSH_CODE (INSTR::INDEX_ID_NARGOUT0);
-  else if (NARGOUT () == 1)
-    PUSH_CODE (INSTR::INDEX_ID_NARGOUT1);
-  else
-    {
-      PUSH_CODE (INSTR::INDEX_IDN);
-      PUSH_CODE (NARGOUT ());
-    }
-
-  PUSH_CODE (arg ? arg->size () : 0);
-  // The vm need the name of the identifier for function lookups
-  PUSH_CODE (SLOT (id_name));
-
-  LOC (loc_id).m_ip_end = CODE_SIZE ();
-  LOC (loc_id).m_col = expr.column ();
-  LOC (loc_id).m_line = expr.line ();
-
-  DEC_DEPTH ();
-}
-#endif
-
 void
 bytecode_walker::
 visit_anon_fcn_handle (tree_anon_fcn_handle &expr)
@@ -3952,11 +4145,11 @@
   if (obj_has_end)
     {
       std::string obj_stack_depth_name = "%objsd_" + std::to_string (CODE_SIZE ());
-      add_id_to_table (obj_stack_depth_name);
-
+      obj_stack_depth_slot = add_id_to_table (obj_stack_depth_name);
+
+      MAYBE_PUSH_WIDE_OPEXT (obj_stack_depth_slot);
       PUSH_CODE (INSTR::SET_SLOT_TO_STACK_DEPTH);
-      obj_stack_depth_slot = SLOT (obj_stack_depth_name);
-      PUSH_CODE (obj_stack_depth_slot);
+      PUSH_SLOT (obj_stack_depth_slot);
     }
 
   // We want to push the args to the stack
@@ -4121,66 +4314,87 @@
       CHECK (e->is_identifier ());
 
       std::string id_name = e->name ();
-
+      int slot = SLOT (id_name);
+      MAYBE_PUSH_WIDE_OPEXT (slot);
       PUSH_CODE (INSTR::WORDCMD);
+      // The vm need the name of the identifier for function lookups
+      PUSH_SLOT (slot);
       PUSH_CODE (nargout);
-
       // Push nargin
-
       PUSH_CODE (args ? args->size () : 0);
-      // The vm need the name of the identifier for function lookups
-      PUSH_CODE (SLOT (id_name));
     }
   else if (e->is_identifier () && !(type == '.' && !struct_is_id_dot_id))
     {
       std::string id_name = e->name ();
+      int slot = SLOT (id_name);
+
       if (type == '(')
         {
           if (nargout == 0)
-            PUSH_CODE (INSTR::INDEX_ID_NARGOUT0);
+            {
+              MAYBE_PUSH_WIDE_OPEXT (slot);
+              PUSH_CODE (INSTR::INDEX_ID_NARGOUT0);
+              // The vm need the name of the identifier for function lookups
+              PUSH_SLOT (slot);
+            }
           else if (nargout == 1)
             {
               // If the id is "sin", "cos", "round" etc, and there is one argument,
               // in the end map(unary_mapper_t) will be called while executing,
               // unless the user have overriden those.
               // We do a special opcode for those to speed them up.
+              // Don't do the special opcode if it would need wide slots, i.e. slot nr > 256.
               auto umaped_fn_it = m_name_to_unary_func.find (id_name);
-              if (!args || args->size () != 1 || umaped_fn_it == m_name_to_unary_func.end ())
-                PUSH_CODE (INSTR::INDEX_ID_NARGOUT1);
+              if (!args || args->size () != 1 || umaped_fn_it == m_name_to_unary_func.end () || slot > 256)
+                {
+                  MAYBE_PUSH_WIDE_OPEXT (slot);
+                  PUSH_CODE (INSTR::INDEX_ID_NARGOUT1);
+                }
               else
                 {
                   octave_base_value::unary_mapper_t idx = umaped_fn_it->second;
                   PUSH_CODE (INSTR::INDEX_ID1_MATHY_UFUN);
                   PUSH_CODE (static_cast<int> (idx));
                 }
+
+              PUSH_SLOT (slot);
             }
           else
             {
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::INDEX_IDN);
+              PUSH_SLOT (slot);
               PUSH_CODE (nargout);
             }
 
           // Push nargin
           PUSH_CODE (args ? args->size () : 0);
-          // The vm need the name of the identifier for function lookups
-          PUSH_CODE (SLOT (id_name));
         }
       else if (type == '{')
         {
           if (nargout == 0)
-            PUSH_CODE (INSTR::INDEX_CELL_ID_NARGOUT0);
+            {
+              MAYBE_PUSH_WIDE_OPEXT (slot);
+              PUSH_CODE (INSTR::INDEX_CELL_ID_NARGOUT0);
+              // The vm need the name of the identifier for function lookups
+              PUSH_SLOT (slot);
+            }
           else if (nargout == 1)
-            PUSH_CODE (INSTR::INDEX_CELL_ID_NARGOUT1);
+            {
+              MAYBE_PUSH_WIDE_OPEXT (slot);
+              PUSH_CODE (INSTR::INDEX_CELL_ID_NARGOUT1);
+              PUSH_SLOT (slot);
+            }
           else
             {
+              MAYBE_PUSH_WIDE_OPEXT (slot);
               PUSH_CODE (INSTR::INDEX_CELL_ID_NARGOUTN);
+              PUSH_SLOT (slot);
               PUSH_CODE (nargout);
             }
 
           // Push nargin
           PUSH_CODE (args ? args->size () : 0);
-          // The vm need the name of the identifier for function lookups
-          PUSH_CODE (SLOT (id_name));
         }
       else if (type == '.')
         {
@@ -4191,8 +4405,8 @@
           CHECK (field_names.numel ());
           std::string field_name = field_names.elem (0);
 
-          PUSH_CODE (SLOT (id_name));    // id to index
-          PUSH_CODE (SLOT (field_name)); // VM need name of the field
+          PUSH_WSLOT (slot);   // id to index
+          PUSH_WSLOT (SLOT (field_name)); // VM need name of the field
         }
       else
         TODO ("Not implemeted typetag");
@@ -4205,7 +4419,7 @@
       PUSH_CODE (INSTR::INDEX_OBJ);
       PUSH_CODE (nargout);
       PUSH_CODE (0); // "has slot"
-      PUSH_CODE (0); // The w/e slot
+      PUSH_WSLOT (0); // The w/e slot TODO: Remove?
       // Push nargin
       if (type == '.')
         PUSH_CODE (1); // Nargin always one for struct indexing
@@ -4357,17 +4571,21 @@
 
   arg_name_entry.m_ip_start = CODE_SIZE ();
 
-  PUSH_CODE (INSTR::INDEX_STRUCT_CALL);
-  PUSH_CODE (nargout);
   if (first_expression && first_expression->is_identifier ())
     {
+      int slot = SLOT (first_expression->name ());
+      MAYBE_PUSH_WIDE_OPEXT (slot);
+      PUSH_CODE (INSTR::INDEX_STRUCT_CALL);
+      PUSH_SLOT (slot); // the slot
       PUSH_CODE (1); // has slot
-      PUSH_CODE (SLOT (first_expression->name ())); // the slot
+      PUSH_CODE (nargout);
     }
   else
     {
+      PUSH_CODE (INSTR::INDEX_STRUCT_CALL);
+      PUSH_SLOT (0); // slot
       PUSH_CODE (0); // has slot
-      PUSH_CODE (0); // slot
+      PUSH_CODE (nargout);
     }
 
   PUSH_CODE (v_n_args.size ());
@@ -4379,7 +4597,7 @@
 
   arg_name_entry.m_ip_end = CODE_SIZE ();
   PUSH_ARGNAMES_ENTRY (arg_name_entry);
-  arg_name_entry = {}; // Reset it for next iteration of the loop
+  arg_name_entry = {}; // TODO: Remove?
 
   LOC (loc_id).m_ip_end = CODE_SIZE ();
   LOC (loc_id).m_col = expr.column ();
@@ -4432,7 +4650,7 @@
   std::string id_name = lhs->name ();
   // We don't want the id pushed to the stack so we
   // don't walk it.
-  add_id_to_table (id_name);
+  int slot = add_id_to_table (id_name);
 
   tree_expression *expr = cmd.control_expr ();
   CHECK_NONNULL (expr);
@@ -4471,11 +4689,12 @@
   // FOR_SETUP uses FOR_COND's operands the first loop iteration
   PUSH_TREE_FOR_DBG (&cmd); // Debug hit at condition
   int cond_offset = CODE_SIZE ();
+  MAYBE_PUSH_WIDE_OPEXT (slot);
   PUSH_CODE (INSTR::FOR_COND);
+  PUSH_SLOT (slot); // The for loop variable
   int need_after = CODE_SIZE ();
   PUSH_CODE_SHORT (-1); // Placeholder for after address
-  PUSH_CODE (SLOT (id_name)); // The for loop variable
-
+ 
   LOC (loc_id).m_ip_end = CODE_SIZE ();
   LOC (loc_id).m_col = cmd.column ();
   LOC (loc_id).m_line = cmd.line ();
@@ -4486,6 +4705,7 @@
   // The body can be empty
   if (list)
     {
+      m_n_nested_loops++;
       PUSH_NESTING_STATEMENT (nesting_statement::FOR_LOOP);
       PUSH_BREAKS ();
       PUSH_CONTINUE_TARGET ();
@@ -4493,6 +4713,7 @@
       for (int offset : POP_CONTINUE_TARGET())
         SET_CODE_SHORT (offset, cond_offset);
       POP_NESTING_STATEMENT ();
+      m_n_nested_loops--;
     }
 
   // A new loc for the for loop suffix code, so that any time
@@ -4594,14 +4815,15 @@
   PUSH_CODE (INSTR::FOR_COMPLEX_COND);
   int need_after1 = CODE_SIZE ();
   PUSH_CODE_SHORT (-1); // Placeholder for after address
-  PUSH_CODE (SLOT (key_name));
-  PUSH_CODE (SLOT (val_name));
+  PUSH_WSLOT (SLOT (key_name));
+  PUSH_WSLOT (SLOT (val_name));
 
   // Walk body
   tree_statement_list *list = cmd.body ();
     // The body can be empty
   if (list)
     {
+      m_n_nested_loops++;
       PUSH_NESTING_STATEMENT (nesting_statement::FOR_LOOP);
       PUSH_BREAKS ();
       PUSH_CONTINUE_TARGET ();
@@ -4609,6 +4831,7 @@
       for (int offset : POP_CONTINUE_TARGET())
         SET_CODE_SHORT (offset, cond_offset);
       POP_NESTING_STATEMENT ();
+      m_n_nested_loops--;
     }
 
   // Jump to condition block, TODO: unless all paths terminated
@@ -4652,10 +4875,11 @@
     TODO ("No support for method fcn handles yet");
 
   // slot for the handle function cache
-  add_id_to_table(aname);
-
+  int slot = add_id_to_table(aname);
+
+  MAYBE_PUSH_WIDE_OPEXT (slot);
   PUSH_CODE (INSTR::PUSH_FCN_HANDLE);
-  PUSH_CODE (SLOT (aname));
+  PUSH_SLOT (slot);
 
   maybe_emit_bind_ans_and_disp (handle);
 
--- a/libinterp/parse-tree/pt-bytecode-walk.h	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-walk.h	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 1996-2022 The Octave Project Developers
+// Copyright (C) 2022-2023 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -169,6 +169,7 @@
     int m_depth = 0;
     int m_offset_n_locals = -1;
     int m_n_locals = 0;
+    int m_n_nested_loops = 0;
 
     // Counter to choose different alternative op-codes in a try to help branch prediction
     int m_cnt_alts_cst = 0;
@@ -184,6 +185,11 @@
     int m_ignored_of_total = 0;
     std::vector<int> m_v_ignored;
 
+    //
+    bool m_is_folding = false;
+    std::vector<tree*> m_v_trees_to_fold;
+    std::vector<int> m_v_offset_of_folds;
+    int m_n_folds = 0;
 
     std::map<std::string, int> m_map_locals_to_slot;
 
@@ -192,7 +198,7 @@
 
     static std::map<std::string, octave_base_value::unary_mapper_t> m_name_to_unary_func;
 
-    void add_id_to_table (std::string name);
+    int add_id_to_table (std::string name);
 
     int n_on_stack_due_to_stmt ();
 
--- a/libinterp/parse-tree/pt-bytecode.h	Mon Jun 19 16:35:32 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode.h	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 2001-2022 The Octave Project Developers
+// Copyright (C) 2022-2023 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -178,6 +178,9 @@
   USUB_DBL,
   NOT_DBL,
   NOT_BOOL,
+  PUSH_FOLDED_CST,
+  SET_FOLDED_CST,
+  WIDE,
 };
 
 enum class unwind_entry_type
@@ -272,6 +275,7 @@
   INVALID_N_EL_RHS_IN_ASSIGNMENT,
   RHS_UNDEF_IN_ASSIGNMENT,
   BAD_ALLOC,
+  EXIT_EXCEPTION,
 };
 
 enum class global_type
--- a/test/compile-bench/bench-octave/bench.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile-bench/bench-octave/bench.m	Mon Jun 19 20:07:05 2023 -0400
@@ -21,6 +21,7 @@
     {"bench_median", {"rand rowvec", 1927}, 1, {}},
     {"bench_cov", {"rand rowvec", 15261}, 1, {}},
     {"str_mod", {"n", 2335290}, 1, {}},
+    {"fib", {"n", 31}, 1, {}},
   };
 
   reg = '';
--- a/test/compile-bench/bench-py3/bench.py	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile-bench/bench-py3/bench.py	Mon Jun 19 20:07:05 2023 -0400
@@ -5,6 +5,12 @@
 import random
 import math
 
+def fib (n):
+    if n <= 1:
+        return 1
+
+    return fib (n - 1) + fib (n - 2)
+
 def for_loop_empty (n):
     for i in range (1, n + 1):
         continue
@@ -128,6 +134,7 @@
     [for_loop_ifs, 5874007],
     [while_loop_empty, 24237997],
     [for_loop_subfun_1, 11930390],
+    [fib, 31],
     [qsort_iterative, "rowvec", 344418]]
 
 def main():
--- a/test/compile-bench/module.mk	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile-bench/module.mk	Mon Jun 19 20:07:05 2023 -0400
@@ -3,6 +3,7 @@
   %reldir%/compile-bench/bench-octave/bench_cov.m\
   %reldir%/compile-bench/bench-octave/bench_median.m\
   %reldir%/compile-bench/bench-octave/do_until_loop_empty.m\
+  %reldir%/compile-bench/bench-octave/fib.m\
   %reldir%/compile-bench/bench-octave/for_loop_binop_1.m\
   %reldir%/compile-bench/bench-octave/for_loop_empty.m\
   %reldir%/compile-bench/bench-octave/for_loop_fncall.m\
--- a/test/compile/bytecode.tst	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode.tst	Mon Jun 19 20:07:05 2023 -0400
@@ -1,6 +1,6 @@
 ########################################################################
 ##
-## Copyright (C) 2006-2022 The Octave Project Developers
+## Copyright (C) 2022-2023 The Octave Project Developers
 ##
 ## See the file COPYRIGHT.md in the top-level directory of this
 ## distribution or <https://octave.org/copyright/>.
@@ -31,7 +31,7 @@
 %! % double's display. Is this a bug ???
 %! clear classes
 
-## licenses binary expression
+## Test binary expressions
 %!test
 %! __enable_vm_eval__ (0, "local"); % Disable the vm for the tree_walker run
 %!
@@ -223,7 +223,7 @@
 %!test
 %! __enable_vm_eval__ (0, "local");
 %! clear all
-%! key = "2 baaar bääär baaaaz bääääz bääääz booz 1 1 2 1 1 1 2 1 silly silly ";
+%! key = "2 baaar bääär baaaaz bääääz bååååz booz 1 1 2 1 1 1 2 1 silly silly ";
 %!
 %! __compile bytecode_return clear;
 %! bytecode_return ();
@@ -504,7 +504,7 @@
 %! key = "a:3 b: double 0 0 0 c:3 c:4 a:4 b:1 double 1 1 0 c:5 c:6 ";
 %! assert (__compile ("bytecode_persistant"));
 %! bytecode_persistant;
-%! disp ("\n");
+%!
 %! bytecode_persistant;
 %! assert (__prog_output_assert__ (key));
 %!
@@ -515,7 +515,7 @@
 %! bytecode_persistant;
 %! __enable_vm_eval__ (1, "local");
 %! assert (__compile ("bytecode_persistant"));
-%! disp ("\n");
+%!
 %! bytecode_persistant;
 %! assert (__prog_output_assert__ (key));
 
--- a/test/compile/bytecode_eval_1.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode_eval_1.m	Mon Jun 19 20:07:05 2023 -0400
@@ -7,7 +7,7 @@
   assert (v == 11);
 
   % ans
-  eval ("12");
+  eval ("12;");
   assert (ans == 12);
 
   % Change variable value
@@ -62,14 +62,14 @@
 
 function sub1()
   % Simple
-  assert (2 == eval ("2"));
+  assert (2 == eval ("2;"));
   assert (2 == eval ("2;"));
 
-  v = eval("11");
+  v = eval("11;");
   assert (v == 11);
 
   % ans
-  eval ("12");
+  eval ("12;");
   assert (ans == 12);
 
   % Change variable value
--- a/test/compile/bytecode_leaks.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode_leaks.m	Mon Jun 19 20:07:05 2023 -0400
@@ -21,9 +21,9 @@
   assert (refs_e, __ref_count (e))
 
   % varargin
-  suby4 (e,e,e,e)
+  suby4 (e,e,e,e);
   assert (refs_e, __ref_count (e))
-  suby5 (e,e,e,e)
+  suby5 (e,e,e,e);
   assert (refs_e, __ref_count (e))
 
   % varargout
@@ -63,11 +63,15 @@
   assert (refs_e, __ref_count (e))
 
   % "command call" with disp
-  e
+  disp ("The disp of e and pi underneath is on purpose. There should be a 'e = 2' and 'ans = 3.14...'")
+  e % Should print "e = 2"
   assert (refs_e + 1, __ref_count (e)) % in ans
   ans = 0;
   assert (refs_e, __ref_count (e))
 
+  % This will be a function call and should print "ans = 3.14..."
+  pi
+
   % no disp
   e;
   assert (refs_e + 1, __ref_count (e)) % in ans
--- a/test/compile/bytecode_misc.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode_misc.m	Mon Jun 19 20:07:05 2023 -0400
@@ -1,11 +1,121 @@
 function bytecode_misc ()
-  ## Assure "set_internal_variable" are reset properly
+  % Assure "set_internal_variable" are reset properly
   max_stack = max_stack_depth;
   set_max_stack_depth_1p (max_stack + 1);
   assert (max_stack_depth == max_stack);
+
+  % Check that the WIDE opcode extension works
+  wide_sub();
+
+  % Try to run out of allowed number of stack frames
+  threw_up = false;
+  try
+    stack_overflow (max_stack * 2); % Should hit the limit
+  catch
+    threw_up = true;
+  end
+
+  assert (threw_up);
+
+  % Try to run out of VM stack space
+  % Assure that the VM is running, since we will disable the tree_evaluators
+  % stack limit mechanism.
+  if __vm_is_executing ()
+    absurd_frame_limit = max_stack_depth * 10000;
+    max_stack_depth (absurd_frame_limit, "local");
+
+    threw_up = false;
+    try
+      stack_overflow (absurd_frame_limit); % Should hit the VM limit
+    catch
+      threw_up = true;
+    end
+    assert (threw_up);
+  end
 end
 
 function set_max_stack_depth_1p (x)
   max_stack_depth (x + 1, "local");
   assert (max_stack_depth == x + 1);
+end
+
+function stack_overflow (n)
+  if n != 0
+    stack_overflow (n - 1);
+  end
+end
+
+function wide_sub ()
+  % 512 locals
+  a001=1; a002=2; a003=3; a004=4; a005=5; a006=6; a007=7; a008=8; a009=9; a010=10; a011=11; a012=12; a013=13; a014=14; a015=15; a016=16; a017=17; a018=18; a019=19; a020=20; a021=21; a022=22; a023=23; a024=24; a025=25; a026=26; a027=27; a028=28; a029=29; a030=30; a031=31; a032=32; a033=33; a034=34; a035=35; a036=36; a037=37; a038=38; a039=39; a040=40; a041=41; a042=42; a043=43; a044=44; a045=45; a046=46; a047=47; a048=48; a049=49; a050=50; a051=51; a052=52; a053=53; a054=54; a055=55; a056=56; a057=57; a058=58; a059=59; a060=60; a061=61; a062=62; a063=63; a064=64; a065=65; a066=66; a067=67; a068=68; a069=69; a070=70; a071=71; a072=72; a073=73; a074=74; a075=75; a076=76; a077=77; a078=78; a079=79; a080=80; a081=81; a082=82; a083=83; a084=84; a085=85; a086=86; a087=87; a088=88; a089=89; a090=90; a091=91; a092=92; a093=93; a094=94; a095=95; a096=96; a097=97; a098=98; a099=99; a100=100; a101=101; a102=102; a103=103; a104=104; a105=105; a106=106; a107=107; a108=108; a109=109; a110=110; a111=111; a112=112; a113=113; a114=114; a115=115; a116=116; a117=117; a118=118; a119=119; a120=120; a121=121; a122=122; a123=123; a124=124; a125=125; a126=126; a127=127; a128=128; a129=129; a130=130; a131=131; a132=132; a133=133; a134=134; a135=135; a136=136; a137=137; a138=138; a139=139; a140=140; a141=141; a142=142; a143=143; a144=144; a145=145; a146=146; a147=147; a148=148; a149=149; a150=150; a151=151; a152=152; a153=153; a154=154; a155=155; a156=156; a157=157; a158=158; a159=159; a160=160; a161=161; a162=162; a163=163; a164=164; a165=165; a166=166; a167=167; a168=168; a169=169; a170=170; a171=171; a172=172; a173=173; a174=174; a175=175; a176=176; a177=177; a178=178; a179=179; a180=180; a181=181; a182=182; a183=183; a184=184; a185=185; a186=186; a187=187; a188=188; a189=189; a190=190; a191=191; a192=192; a193=193; a194=194; a195=195; a196=196; a197=197; a198=198; a199=199; a200=200; a201=201; a202=202; a203=203; a204=204; a205=205; a206=206; a207=207; a208=208; a209=209; a210=210; a211=211; a212=212; a213=213; a214=214; a215=215; a216=216; a217=217; a218=218; a219=219; a220=220; a221=221; a222=222; a223=223; a224=224; a225=225; a226=226; a227=227; a228=228; a229=229; a230=230; a231=231; a232=232; a233=233; a234=234; a235=235; a236=236; a237=237; a238=238; a239=239; a240=240; a241=241; a242=242; a243=243; a244=244; a245=245; a246=246; a247=247; a248=248; a249=249; a250=250; a251=251; a252=252; a253=253; a254=254; a255=255; a256=256; a257=257; a258=258; a259=259; a260=260; a261=261; a262=262; a263=263; a264=264; a265=265; a266=266; a267=267; a268=268; a269=269; a270=270; a271=271; a272=272; a273=273; a274=274; a275=275; a276=276; a277=277; a278=278; a279=279; a280=280; a281=281; a282=282; a283=283; a284=284; a285=285; a286=286; a287=287; a288=288; a289=289; a290=290; a291=291; a292=292; a293=293; a294=294; a295=295; a296=296; a297=297; a298=298; a299=299; a300=300; a301=301; a302=302; a303=303; a304=304; a305=305; a306=306; a307=307; a308=308; a309=309; a310=310; a311=311; a312=312; a313=313; a314=314; a315=315; a316=316; a317=317; a318=318; a319=319; a320=320; a321=321; a322=322; a323=323; a324=324; a325=325; a326=326; a327=327; a328=328; a329=329; a330=330; a331=331; a332=332; a333=333; a334=334; a335=335; a336=336; a337=337; a338=338; a339=339; a340=340; a341=341; a342=342; a343=343; a344=344; a345=345; a346=346; a347=347; a348=348; a349=349; a350=350; a351=351; a352=352; a353=353; a354=354; a355=355; a356=356; a357=357; a358=358; a359=359; a360=360; a361=361; a362=362; a363=363; a364=364; a365=365; a366=366; a367=367; a368=368; a369=369; a370=370; a371=371; a372=372; a373=373; a374=374; a375=375; a376=376; a377=377; a378=378; a379=379; a380=380; a381=381; a382=382; a383=383; a384=384; a385=385; a386=386; a387=387; a388=388; a389=389; a390=390; a391=391; a392=392; a393=393; a394=394; a395=395; a396=396; a397=397; a398=398; a399=399; a400=400; a401=401; a402=402; a403=403; a404=404; a405=405; a406=406; a407=407; a408=408; a409=409; a410=410; a411=411; a412=412; a413=413; a414=414; a415=415; a416=416; a417=417; a418=418; a419=419; a420=420; a421=421; a422=422; a423=423; a424=424; a425=425; a426=426; a427=427; a428=428; a429=429; a430=430; a431=431; a432=432; a433=433; a434=434; a435=435; a436=436; a437=437; a438=438; a439=439; a440=440; a441=441; a442=442; a443=443; a444=444; a445=445; a446=446; a447=447; a448=448; a449=449; a450=450; a451=451; a452=452; a453=453; a454=454; a455=455; a456=456; a457=457; a458=458; a459=459; a460=460; a461=461; a462=462; a463=463; a464=464; a465=465; a466=466; a467=467; a468=468; a469=469; a470=470; a471=471; a472=472; a473=473; a474=474; a475=475; a476=476; a477=477; a478=478; a479=479; a480=480; a481=481; a482=482; a483=483; a484=484; a485=485; a486=486; a487=487; a488=488; a489=489; a490=490; a491=491; a492=492; a493=493; a494=494; a495=495; a496=496; a497=497; a498=498; a499=499; a500=500; a501=501; a502=502; a503=503; a504=504; a505=505; a506=506; a507=507; a508=508; a509=509; a510=510; a511=511; a512=512;
+
+  assert (a511 == 511);
+  assert (a512 == 512);
+  assert (a400 + a500 == 900);
+
+  % Do some ops to check that WIDE does not mess things up
+
+  % Loop to test specializations and despecializations
+  for j = 1:4
+    b = 3;
+    c = 4;
+    d = b * c;
+    assert (d == 12);
+
+    e = [1 2 3 4];
+    two = 2;
+    if (j == 3)
+      e = single (e); % despecialization
+      two = single (two);
+    end
+
+    assert (e(2) == 2);
+    assert (e(2) == two);
+    e(3) = 11;
+    assert (e(3) == 11);
+
+    assert (e(end) == 4);
+    assert (e(end - 1) == 11);
+
+    f = [5 6 7 8; 9 10 11 12];
+    six = 6;
+    if (j == 3)
+      f = single (f); % despecialization
+      six = single (six);
+    end
+    assert (f(1,2) == 6);
+    assert (f(1,2) == six);
+    f(1,2) = 7;
+    assert (f(1,2) == 7);
+
+    g = 0;
+    if (j == 3)
+      g = single (g); % despecialization
+    end
+
+    g++;
+    assert (g == 1);
+    ++g;
+    assert (g == 2);
+    g += 3;
+    assert (g == 5);
+    eval ("assert (g == 5);")
+
+    sum = 0;
+    for i = 1:3 % WIDE FOR_COND
+      sum += i;
+    end
+    assert (sum == 6);
+
+    s.s = 2;
+    assert (s.s == 2);
+    s.w.s = 3;
+    assert (s.w.s == 3);
+  end
+
+
+  % Check that a001 to a512 have to correct values
+  for i = 1:512
+    eval (sprintf ("assert (a%03d == %d);", i, i));
+  end
 end
\ No newline at end of file
--- a/test/compile/bytecode_return.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode_return.m	Mon Jun 19 20:07:05 2023 -0400
@@ -4,6 +4,7 @@
 
   bar (1);
   bar (0);
+
   baz (0);
   baz (1);
   baz (2);
@@ -25,7 +26,6 @@
   % Drop all output variables
   return_2 ();
 
-
   % Command form call
   a = return_1;
   __printf_assert__ ("%d ", a);
@@ -74,7 +74,7 @@
   if i == 0
     __printf_assert__ ("baaaaz ");
     return
-  else i == 1
+  elseif i == 1
     __printf_assert__ ("bääääz ");
     return
   end
--- a/test/compile/bytecode_subfuncs.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode_subfuncs.m	Mon Jun 19 20:07:05 2023 -0400
@@ -47,14 +47,14 @@
 
   % Many args and returns
   [a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32] = ret32 ();
-  __printf_assert__ ("%d ", a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32)
+  __printf_assert__ ("%d ", a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32);
   __printf_assert__ ("%d ", ret32 ()); % nargout = 1
-  ret32 () % nargout = 0
+  ret32 (); % nargout = 0
   [args32{1:32}] = ret32 ();
-  __printf_assert__ ("%d ", args32{:})
+  __printf_assert__ ("%d ", args32{:});
 
   [a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32] = ret32take32 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
-  __printf_assert__ ("%d ", a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32)
+  __printf_assert__ ("%d ", a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32);
 
   take32 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
 
@@ -62,7 +62,7 @@
    a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63, a64] = ...
       takeXp32retXp32 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ...
                        33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64);
-  __printf_assert__ ("%d ", a01, a18, a59, a64)
+  __printf_assert__ ("%d ", a01, a18, a59, a64);
 end
 
 function [a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, varargout] = takeXp32retXp32 (b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, varargin)
--- a/test/compile/bytecode_varargout.m	Mon Jun 19 16:35:32 2023 -0400
+++ b/test/compile/bytecode_varargout.m	Mon Jun 19 20:07:05 2023 -0400
@@ -1,5 +1,5 @@
 function bytecode_varargout ()
-        disp ("foobar")
+
     % Just check this works
     [a b] = {7, 8}{:};
     __printf_assert__ ("%d %d ", a, b);
@@ -20,10 +20,10 @@
 
     [a b c] = return_isargout (4);
     __printf_assert__ ("%d ", a);
- disp ("foobar2")
+
     [a, ~, c] = return_isargout (2);
     __printf_assert__ ("%d ", a);
- disp ("foobar22")
+
     [a, ~, ~] = return_isargout (2);
     __printf_assert__ ("%d ", a);
     [a, ~, ~] = return_isargout (1);