changeset 32317:906ea9c9c5d9

VM Fix chained subsassigns keeping a value live on the stack (Bug #64557) Give SUBASSIGN_CHAINED access to slot number, so that it can assign to a identifier inplace, to not waste memory. * libinterp/parse-tree/pt-bytecode-vm.cc: Restructure how SUBASSIGN_CHAINED works * libinterp/parse-tree/pt-bytecode-walk.cc: Slot for SUBASSIGN_CHAINED Nullptr check for args
author Petter T. <petter.vilhelm@gmail.com>
date Wed, 20 Sep 2023 20:00:21 -0400
parents 8d3b15dd7505
children ddf7c5f4ddde
files libinterp/parse-tree/pt-bytecode-vm.cc libinterp/parse-tree/pt-bytecode-walk.cc
diffstat 2 files changed, 35 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-bytecode-vm.cc	Wed Sep 20 19:56:02 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-vm.cc	Wed Sep 20 20:00:21 2023 -0400
@@ -433,6 +433,7 @@
           CASE_END ()
 
           CASE_START (SUBASSIGN_CHAINED)
+            PSLOT ();
             PCHAR (); // op
             PCHAR (); // nchained
             int nn = *p;
@@ -5639,7 +5640,8 @@
 
 subassign_chained:
   {
-    octave_value::assign_op op = static_cast<octave_value::assign_op> (arg0);
+    int slot = arg0;
+    octave_value::assign_op op = static_cast<octave_value::assign_op> (*ip++);
     int n_chained = POP_CODE ();
     std::vector<int> v_n_args;
     std::string type (n_chained, 0);
@@ -5684,15 +5686,36 @@
         if (type.size () && type.back () != '(' && lhs_assign_numel (lhs, type, idx) != 1)
           err_invalid_structure_assignment ();
 
-        lhs.assign (op, type, idx, rhs);
+        if (slot)
+          {
+            octave_value &lhs_slot = bsp[slot].ov;
+
+            // We don't need to he lhs value put on the stack since we are working on a slot.
+            // Clear it to make assigns not need a new copy.
+            lhs = octave_value {};
+
+            bool is_ref = lhs_slot.is_ref ();
+
+            if (is_ref)
+              lhs_slot.ref_rep ()->ref ().make_unique ();
+
+            lhs_slot.assign (op, type, idx, rhs);
+
+            // Push a dummy octave_value. Always poped by a POP opcode. 
+            PUSH_OV (octave_value {});
+          }
+        else
+          {
+            lhs.assign (op, type, idx, rhs);
+            // The value is pushed and used for further chaining.
+            PUSH_OV (lhs);
+          }
       }
     CATCH_INTERRUPT_EXCEPTION
     CATCH_INDEX_EXCEPTION
     CATCH_EXECUTION_EXCEPTION
     CATCH_BAD_ALLOC
     CATCH_EXIT_EXCEPTION
-
-    PUSH_OV (lhs);
   }
   DISPATCH ();
 
--- a/libinterp/parse-tree/pt-bytecode-walk.cc	Wed Sep 20 19:56:02 2023 -0400
+++ b/libinterp/parse-tree/pt-bytecode-walk.cc	Wed Sep 20 20:00:21 2023 -0400
@@ -3359,7 +3359,7 @@
 
               n_args_in_part++;
             }
-          else
+          else if (args)
             {
               // Push all the args to the stack
 
@@ -3413,7 +3413,13 @@
       // We want to put them in lists and feed them to a subsassgn() call. We use
       // a special op-code for this.
 
+      int slot = 0;
+      if (e->is_identifier ())
+        slot = SLOT (e->name ());
+
+      MAYBE_PUSH_WIDE_OPEXT (slot);
       PUSH_CODE (INSTR::SUBASSIGN_CHAINED);
+      PUSH_SLOT (slot);
       PUSH_CODE (op); // =, += etc.
       PUSH_CODE (n_chained);
       for (unsigned i = 0; i < n_chained; i++)
@@ -3426,11 +3432,7 @@
       // Now we got the value that is subassigned to, on the stack
       if (e->is_identifier ())
         {
-          // Write the subassigned value back to the slot
-          int slot = SLOT (e->name ());
-          MAYBE_PUSH_WIDE_OPEXT (slot);
-          PUSH_CODE (INSTR::FORCE_ASSIGN);
-          PUSH_SLOT (slot);
+          PUSH_CODE (INSTR::POP);
 
           maybe_emit_push_and_disp_id (expr, e->name ());
         }