# HG changeset patch # User Petter T. # Date 1695044717 -7200 # Mon Sep 18 15:45:17 2023 +0200 # Node ID f7eaf872975ec1e7e5c7369ed7d31dd2f9d3f890 # Parent b4b015238ebc5f3056c96283af3f951efdfa8561 VM Fix chained subsassigns keeping a value live on the stack. 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 diff -r b4b015238ebc -r f7eaf872975e libinterp/parse-tree/pt-bytecode-vm.cc --- a/libinterp/parse-tree/pt-bytecode-vm.cc Tue Sep 19 22:28:24 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode-vm.cc Mon Sep 18 15:45:17 2023 +0200 @@ -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 (arg0); + int slot = arg0; + octave_value::assign_op op = static_cast (*ip++); int n_chained = POP_CODE (); std::vector 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 (); diff -r b4b015238ebc -r f7eaf872975e libinterp/parse-tree/pt-bytecode-walk.cc --- a/libinterp/parse-tree/pt-bytecode-walk.cc Tue Sep 19 22:28:24 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode-walk.cc Mon Sep 18 15:45:17 2023 +0200 @@ -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 ()); }