# HG changeset patch
# User Petter Tomner <tomner@kth.se>
# Date 1641085730 -3600
#      Sun Jan 02 02:08:50 2022 +0100
# Node ID 94435aa4d28ca8265b101ff52b579fb18af71a72
# Parent  09b9d28935be3e94f42ca1dbfa5797a0e19c14a7
interpreter: Non-virtual calls in op:s and ov inline constructor

Speed up operators by doing non-virtual calls in the operator
definitions and use builder functions for octave_values that
are inlinable.

Make some getters final to avoid derived classes overriding
and messing up the direct calls in the operator definitions.

libinterp/octave-value/
	* ov-inline.h: New. "Factory" class.
	* ov-complex.h: Mark final
	* ov-scalar.h
	* ov.h: Private inlinable constructor
libinterp/operators/
	* op-b-b.cc: Use factory
	* op-cs-cs.cc
	* op-cs-s.cc
	* op-s-cs.cc
	* op-s-s.cc
	* ops.h: Macros for factory usage, direct calls

diff -r 09b9d28935be -r 94435aa4d28c libinterp/octave-value/ov-complex.h
--- a/libinterp/octave-value/ov-complex.h	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/octave-value/ov-complex.h	Sun Jan 02 02:08:50 2022 +0100
@@ -128,7 +128,7 @@
   OCTINTERP_API octave_value
   resize (const dim_vector& dv, bool fill = false) const;
 
-  OCTINTERP_API Complex complex_value (bool = false) const;
+  OCTINTERP_API Complex complex_value (bool = false) const final;
 
   OCTINTERP_API FloatComplex float_complex_value (bool = false) const;
 
diff -r 09b9d28935be -r 94435aa4d28c libinterp/octave-value/ov-inline.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-inline.h	Sun Jan 02 02:08:50 2022 +0100
@@ -0,0 +1,125 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 1996-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_ov_inline_h)
+#define octave_ov_inline_h 1
+
+#include "octave-config.h"
+
+#include "ov.h"
+
+#include "ov-scalar.h"
+#include "ov-float.h"
+#include "ov-complex.h"
+#include "ov-flt-complex.h"
+#include "ov-bool.h"
+
+
+// class to construct octave_value:s inline
+
+class octave_value_factory
+{
+  public:
+
+  static octave_value make (double d)
+  {
+    return octave_value (0, new octave_scalar (d));
+  }
+
+  static octave_value make (float d)
+  {
+    return octave_value (0, new octave_float_scalar (d));
+  }
+
+  static octave_value make (short int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+
+  static octave_value make (unsigned short int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+
+  static octave_value make (int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+
+  static octave_value make (unsigned int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+
+  static octave_value make (unsigned long int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+  static octave_value make (long long int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+#endif
+
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+  static octave_value make (unsigned long long int i)
+  {
+    return octave_value (0, new octave_scalar (i));
+  }
+#endif
+
+  static octave_value make (octave::sys::time t)
+  {
+    return octave_value (0, new octave_scalar (t.double_value ()));
+  }
+
+  static octave_value make (const Complex& C)
+  {
+    octave_value ov(0, new octave_complex (C));
+    ov.maybe_mutate (); // Fold e.g. 1+0i to 1
+    return ov;
+  }
+
+  static octave_value make (const FloatComplex& C)
+  {
+    octave_value ov(0, new octave_float_complex (C));
+    ov.maybe_mutate ();
+    return ov;
+  }
+
+  static octave_value make (bool b)
+  {
+    return octave_value (0, new octave_bool (b));
+  }
+
+
+  private:
+  ~octave_value_factory () = delete;
+  octave_value_factory () = delete;
+};
+
+#endif
diff -r 09b9d28935be -r 94435aa4d28c libinterp/octave-value/ov-scalar.h
--- a/libinterp/octave-value/ov-scalar.h	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/octave-value/ov-scalar.h	Sun Jan 02 02:08:50 2022 +0100
@@ -144,7 +144,7 @@
 
 #undef DEFINE_INT_SCALAR_VALUE
 
-  double double_value (bool = false) const { return scalar; }
+  double double_value (bool = false) const final { return scalar; }
 
   float float_value (bool = false) const
   { return static_cast<float> (scalar); }
@@ -203,7 +203,7 @@
     return retval;
   }
 
-  bool bool_value (bool warn = false) const
+  bool bool_value (bool warn = false) const final
   {
     if (octave::math::isnan (scalar))
       octave::err_nan_to_logical_conversion ();
diff -r 09b9d28935be -r 94435aa4d28c libinterp/octave-value/ov.h
--- a/libinterp/octave-value/ov.h	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/octave-value/ov.h	Sun Jan 02 02:08:50 2022 +0100
@@ -289,6 +289,10 @@
   OCTINTERP_API octave_value (const octave::idx_vector& idx, bool lazy = true);
 
 private:
+  // For use by inline octave_value "factory" octave_value_inline
+  octave_value (int /* dummy */, octave_base_value *rep) : m_rep (rep) {}
+
+  friend class octave_value_factory;
 
   // Remove when public constructors that use this function are removed.
   static OCTINTERP_API octave_base_value *
diff -r 09b9d28935be -r 94435aa4d28c libinterp/operators/op-b-b.cc
--- a/libinterp/operators/op-b-b.cc	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/operators/op-b-b.cc	Sun Jan 02 02:08:50 2022 +0100
@@ -81,10 +81,10 @@
 
 // bool by bool ops.
 
-DEFBINOP_OP (eq, bool, bool, ==)
-DEFBINOP_OP (ne, bool, bool, !=)
-DEFBINOP_OP (el_and, bool, bool, &&)
-DEFBINOP_OP (el_or, bool, bool, ||)
+DEFBINOP_SCALAR_OP (eq, bool, bool, ==)
+DEFBINOP_SCALAR_OP (ne, bool, bool, !=)
+DEFBINOP_SCALAR_OP (el_and, bool, bool, &&)
+DEFBINOP_SCALAR_OP (el_or, bool, bool, ||)
 
 DEFNDCATOP_FN (b_b, bool, bool, bool_array, bool_array, concat)
 DEFNDCATOP_FN (b_s, bool, scalar, array, array, concat)
diff -r 09b9d28935be -r 94435aa4d28c libinterp/operators/op-cs-cs.cc
--- a/libinterp/operators/op-cs-cs.cc	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/operators/op-cs-cs.cc	Sun Jan 02 02:08:50 2022 +0100
@@ -51,18 +51,18 @@
   if (octave::math::isnan (x))
     octave::err_nan_to_logical_conversion ();
 
-  return octave_value (x == 0.0);
+  return octave_value_factory::make (x == 0.0);
 }
 
-DEFUNOP_OP (uplus, complex, /* no-op */)
-DEFUNOP_OP (uminus, complex, -)
-DEFUNOP_OP (transpose, complex, /* no-op */)
+DEFUNOP_SCALAR_OP (uplus, complex, /* no-op */)
+DEFUNOP_SCALAR_OP (uminus, complex, -)
+DEFUNOP_SCALAR_OP (transpose, complex, /* no-op */)
 
 DEFUNOP (hermitian, complex)
 {
   const octave_complex& v = DYNORSTAT_CAST<const octave_complex&> (a);
 
-  return octave_value (conj (v.complex_value ()));
+  return octave_value_factory::make (conj (v.octave_complex::complex_value ()));
 }
 
 DEFNCUNOP_METHOD (incr, complex, increment)
@@ -70,26 +70,28 @@
 
 // complex scalar by complex scalar ops.
 
-DEFBINOP_OP (add, complex, complex, +)
-DEFBINOP_OP (sub, complex, complex, -)
-DEFBINOP_OP (mul, complex, complex, *)
+DEFBINOP_SCALAR_OP (add, complex, complex, +)
+DEFBINOP_SCALAR_OP (sub, complex, complex, -)
+DEFBINOP_SCALAR_OP (mul, complex, complex, *)
 
 DEFBINOP (div, complex, complex)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v1.complex_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (pow, complex, complex, xpow)
+DEFBINOP_SCALAR_FN (pow, complex, complex, xpow)
 
 DEFBINOP (ldiv, complex, complex)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v2.complex_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFCMPLXCMPOP_OP (lt, complex, complex, <)
@@ -99,24 +101,26 @@
 DEFCMPLXCMPOP_OP (gt, complex, complex, >)
 DEFCMPLXCMPOP_OP (ne, complex, complex, !=)
 
-DEFBINOP_OP (el_mul, complex, complex, *)
+DEFBINOP_SCALAR_OP (el_mul, complex, complex, *)
 
 DEFBINOP (el_div, complex, complex)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v1.complex_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (el_pow, complex, complex, xpow)
+DEFBINOP_SCALAR_FN (el_pow, complex, complex, xpow)
 
 DEFBINOP (el_ldiv, complex, complex)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v2.complex_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFBINOP (el_and, complex, complex)
@@ -124,7 +128,8 @@
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return v1.complex_value () != 0.0 && v2.complex_value () != 0.0;
+  return v1.octave_complex::complex_value () != 0.0 &&
+    v2.octave_complex::complex_value () != 0.0;
 }
 
 DEFBINOP (el_or, complex, complex)
@@ -132,7 +137,8 @@
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return v1.complex_value () != 0.0 || v2.complex_value () != 0.0;
+  return v1.octave_complex::complex_value () != 0.0 ||
+    v2.octave_complex::complex_value () != 0.0;
 }
 
 DEFNDCATOP_FN (cs_cs, complex, complex, complex_array, complex_array, concat)
diff -r 09b9d28935be -r 94435aa4d28c libinterp/operators/op-cs-s.cc
--- a/libinterp/operators/op-cs-s.cc	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/operators/op-cs-s.cc	Sun Jan 02 02:08:50 2022 +0100
@@ -41,26 +41,28 @@
 
 // complex scalar by scalar ops.
 
-DEFBINOP_OP (add, complex, scalar, +)
-DEFBINOP_OP (sub, complex, scalar, -)
-DEFBINOP_OP (mul, complex, scalar, *)
+DEFBINOP_SCALAR_OP (add, complex, scalar, +)
+DEFBINOP_SCALAR_OP (sub, complex, scalar, -)
+DEFBINOP_SCALAR_OP (mul, complex, scalar, *)
 
 DEFBINOP (div, complex, scalar)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v1.complex_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (pow, complex, scalar, xpow)
+DEFBINOP_SCALAR_FN (pow, complex, scalar, xpow)
 
 DEFBINOP (ldiv, complex, scalar)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v2.double_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFCMPLXCMPOP_OP (lt, complex, scalar, <)
@@ -70,24 +72,26 @@
 DEFCMPLXCMPOP_OP (gt, complex, scalar, >)
 DEFCMPLXCMPOP_OP (ne, complex, scalar, !=)
 
-DEFBINOP_OP (el_mul, complex, scalar, *)
+DEFBINOP_SCALAR_OP (el_mul, complex, scalar, *)
 
 DEFBINOP (el_div, complex, scalar)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v1.complex_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_complex::complex_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (el_pow, complex, scalar, xpow)
+DEFBINOP_SCALAR_FN (el_pow, complex, scalar, xpow)
 
 DEFBINOP (el_ldiv, complex, scalar)
 {
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v2.double_value () / v1.complex_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_complex::complex_value ());
 }
 
 DEFBINOP (el_and, complex, scalar)
@@ -95,7 +99,8 @@
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return v1.complex_value () != 0.0 && v2.double_value ();
+  return v1.octave_complex::complex_value () != 0.0 &&
+    v2.octave_scalar::double_value ();
 }
 
 DEFBINOP (el_or, complex, scalar)
@@ -103,7 +108,8 @@
   const octave_complex& v1 = DYNORSTAT_CAST<const octave_complex&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return v1.complex_value () != 0.0 || v2.double_value ();
+  return v1.octave_complex::complex_value () != 0.0 ||
+    v2.octave_scalar::double_value ();
 }
 
 DEFNDCATOP_FN (cs_s, complex, scalar, complex_array, array, concat)
diff -r 09b9d28935be -r 94435aa4d28c libinterp/operators/op-s-cs.cc
--- a/libinterp/operators/op-s-cs.cc	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/operators/op-s-cs.cc	Sun Jan 02 02:08:50 2022 +0100
@@ -43,26 +43,28 @@
 
 // scalar by complex scalar ops.
 
-DEFBINOP_OP (add, scalar, complex, +)
-DEFBINOP_OP (sub, scalar, complex, -)
-DEFBINOP_OP (mul, scalar, complex, *)
+DEFBINOP_SCALAR_OP (add, scalar, complex, +)
+DEFBINOP_SCALAR_OP (sub, scalar, complex, -)
+DEFBINOP_SCALAR_OP (mul, scalar, complex, *)
 
 DEFBINOP (div, scalar, complex)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v1.double_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (pow, scalar, complex, xpow)
+DEFBINOP_SCALAR_FN (pow, scalar, complex, xpow)
 
 DEFBINOP (ldiv, scalar, complex)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v2.complex_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
 DEFCMPLXCMPOP_OP (lt, scalar, complex, <)
@@ -72,24 +74,26 @@
 DEFCMPLXCMPOP_OP (gt, scalar, complex, >)
 DEFCMPLXCMPOP_OP (ne, scalar, complex, !=)
 
-DEFBINOP_OP (el_mul, scalar, complex, *)
+DEFBINOP_SCALAR_OP (el_mul, scalar, complex, *)
 
 DEFBINOP (el_div, scalar, complex)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v1.double_value () / v2.complex_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_complex::complex_value ());
 }
 
-DEFBINOP_FN (el_pow, scalar, complex, xpow)
+DEFBINOP_SCALAR_FN (el_pow, scalar, complex, xpow)
 
 DEFBINOP (el_ldiv, scalar, complex)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v2.complex_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_complex::complex_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
 DEFBINOP (el_and, scalar, complex)
@@ -97,7 +101,9 @@
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v1.double_value () && (v2.complex_value () != 0.0));
+  return octave_value_factory::make (
+    v1.octave_scalar::double_value () &&
+    (v2.octave_complex::complex_value () != 0.0));
 }
 
 DEFBINOP (el_or, scalar, complex)
@@ -105,7 +111,9 @@
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_complex& v2 = DYNORSTAT_CAST<const octave_complex&> (a2);
 
-  return octave_value (v1.double_value () || (v2.complex_value () != 0.0));
+  return octave_value_factory::make (
+    v1.octave_scalar::double_value () ||
+    (v2.octave_complex::complex_value () != 0.0));
 }
 
 DEFNDCATOP_FN (s_cs, scalar, complex, array, complex_array, concat)
diff -r 09b9d28935be -r 94435aa4d28c libinterp/operators/op-s-s.cc
--- a/libinterp/operators/op-s-s.cc	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/operators/op-s-s.cc	Sun Jan 02 02:08:50 2022 +0100
@@ -52,66 +52,70 @@
   if (octave::math::isnan (x))
     octave::err_nan_to_logical_conversion ();
 
-  return octave_value (x == 0.0);
+  return octave_value_factory::make (x == 0.0);
 }
 
-DEFUNOP_OP (uplus, scalar, /* no-op */)
-DEFUNOP_OP (uminus, scalar, -)
-DEFUNOP_OP (transpose, scalar, /* no-op */)
-DEFUNOP_OP (hermitian, scalar, /* no-op */)
+DEFUNOP_SCALAR_OP (uplus, scalar, /* no-op */)
+DEFUNOP_SCALAR_OP (uminus, scalar, -)
+DEFUNOP_SCALAR_OP (transpose, scalar, /* no-op */)
+DEFUNOP_SCALAR_OP (hermitian, scalar, /* no-op */)
 
 DEFNCUNOP_METHOD (incr, scalar, increment)
 DEFNCUNOP_METHOD (decr, scalar, decrement)
 
 // scalar by scalar ops.
 
-DEFBINOP_OP (add, scalar, scalar, +)
-DEFBINOP_OP (sub, scalar, scalar, -)
-DEFBINOP_OP (mul, scalar, scalar, *)
+DEFBINOP_SCALAR_OP (add, scalar, scalar, +)
+DEFBINOP_SCALAR_OP (sub, scalar, scalar, -)
+DEFBINOP_SCALAR_OP (mul, scalar, scalar, *)
 
 DEFBINOP (div, scalar, scalar)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v1.double_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (pow, scalar, scalar, xpow)
+DEFBINOP_SCALAR_FN (pow, scalar, scalar, xpow)
 
 DEFBINOP (ldiv, scalar, scalar)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v2.double_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
-DEFBINOP_OP (lt, scalar, scalar, <)
-DEFBINOP_OP (le, scalar, scalar, <=)
-DEFBINOP_OP (eq, scalar, scalar, ==)
-DEFBINOP_OP (ge, scalar, scalar, >=)
-DEFBINOP_OP (gt, scalar, scalar, >)
-DEFBINOP_OP (ne, scalar, scalar, !=)
+DEFBINOP_SCALAR_OP (lt, scalar, scalar, <)
+DEFBINOP_SCALAR_OP (le, scalar, scalar, <=)
+DEFBINOP_SCALAR_OP (eq, scalar, scalar, ==)
+DEFBINOP_SCALAR_OP (ge, scalar, scalar, >=)
+DEFBINOP_SCALAR_OP (gt, scalar, scalar, >)
+DEFBINOP_SCALAR_OP (ne, scalar, scalar, !=)
 
-DEFBINOP_OP (el_mul, scalar, scalar, *)
+DEFBINOP_SCALAR_OP (el_mul, scalar, scalar, *)
 
 DEFBINOP (el_div, scalar, scalar)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v1.double_value () / v2.double_value ());
+  return octave_value_factory::make (v1.octave_scalar::double_value () /
+                                     v2.octave_scalar::double_value ());
 }
 
-DEFBINOP_FN (el_pow, scalar, scalar, xpow)
+DEFBINOP_SCALAR_FN (el_pow, scalar, scalar, xpow)
 
 DEFBINOP (el_ldiv, scalar, scalar)
 {
   const octave_scalar& v1 = DYNORSTAT_CAST<const octave_scalar&> (a1);
   const octave_scalar& v2 = DYNORSTAT_CAST<const octave_scalar&> (a2);
 
-  return octave_value (v2.double_value () / v1.double_value ());
+  return octave_value_factory::make (v2.octave_scalar::double_value () /
+                                     v1.octave_scalar::double_value ());
 }
 
 DEFSCALARBOOLOP_OP (el_and, scalar, scalar, &&)
diff -r 09b9d28935be -r 94435aa4d28c libinterp/operators/ops.h
--- a/libinterp/operators/ops.h	Sat Jan 01 13:16:22 2022 +0100
+++ b/libinterp/operators/ops.h	Sun Jan 02 02:08:50 2022 +0100
@@ -29,6 +29,7 @@
 #include "octave-config.h"
 
 #include "Array-util.h"
+#include "ov-inline.h"
 
 namespace octave
 {
@@ -195,6 +196,14 @@
     return octave_value (op v.CONCAT2 (t, _value) ());                  \
   }
 
+#define DEFUNOP_SCALAR_OP(name, t, op)                                         \
+  static octave_value CONCAT2(oct_unop_, name)(const octave_base_value &a) {   \
+    const CONCAT2(octave_, t) &v =                                             \
+        DYNORSTAT_CAST<const CONCAT2(octave_, t) &>(a);                        \
+    return octave_value_factory::make (                                        \
+      op v.CONCAT2 (octave_, t)::CONCAT2 (t, _value) ()); \
+  }
+
 #define DEFNDUNOP_OP(name, t, e, op)                                    \
   static octave_value                                                   \
   CONCAT2 (oct_unop_, name) (const octave_base_value& a)                \
@@ -226,7 +235,7 @@
   CONCAT2 (oct_unop_, name) (octave_base_value& a)                      \
   {                                                                     \
     CONCAT2 (octave_, t)& v = DYNORSTAT_CAST<CONCAT2 (octave_, t)&> (a);  \
-    v.method ();                                                        \
+    v.CONCAT2 (octave_, t)::method ();                                  \
   }
 
 #define DEFBINOPX(name, t1, t2)                         \
@@ -239,6 +248,19 @@
   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,      \
                               const octave_base_value& a2)
 
+#define DEFBINOP_SCALAR_OP(name, t1, t2, op)                               \
+  static octave_value CONCAT2(oct_binop_, name)(const octave_base_value &a1,   \
+                                                const octave_base_value &a2) { \
+    const CONCAT2(octave_, t1) &v1 =                                           \
+        DYNORSTAT_CAST<const CONCAT2(octave_, t1) &>(a1);                      \
+    const CONCAT2(octave_, t2) &v2 =                                           \
+        DYNORSTAT_CAST<const CONCAT2(octave_, t2) &>(a2);                      \
+    /* Note: Not virtual calls */                                              \
+    return octave_value_factory::make                                          \
+      (v1.CONCAT2(octave_, t1)::CONCAT2(t1, _value)() op               \
+       v2.CONCAT2(octave_, t2)::CONCAT2(t2, _value)());                \
+  }
+
 #define DEFBINOP_OP(name, t1, t2, op)                                   \
   static octave_value                                                   \
   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
@@ -260,9 +282,10 @@
     const CONCAT2 (octave_, t2)& v2 = DYNORSTAT_CAST<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     warn_complex_cmp ();                                                \
-                                                                        \
-    return octave_value                                                 \
-      (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
+    /* Note: Not virtual call */                                        \
+    return octave_value_factory::make                                   \
+      (v1.CONCAT2 (octave_, t1)::CONCAT2 (t1, _value) () op             \
+       v2.CONCAT2 (octave_, t2)::CONCAT2 (t2, _value) ());              \
   }
 
 #define DEFSCALARBOOLOP_OP(name, t1, t2, op)                            \
@@ -276,8 +299,9 @@
     if (octave::math::isnan (v1.CONCAT2 (t1, _value) ()) || octave::math::isnan (v2.CONCAT2 (t2, _value) ())) \
       octave::err_nan_to_logical_conversion ();                                 \
                                                                         \
-    return octave_value                                                 \
-      (v1.CONCAT2 (t1, _value) () op v2.CONCAT2 (t2, _value) ());       \
+    return octave_value_factory::make                                   \
+      (v1.CONCAT2 (octave_, t1)::CONCAT2 (t1, _value) () op             \
+       v2.CONCAT2 (octave_, t2)::CONCAT2 (t2, _value) ());    \
   }
 
 #define DEFNDBINOP_OP(name, t1, t2, e1, e2, op)                         \
@@ -305,6 +329,19 @@
     return octave_value (f (v1.CONCAT2 (t1, _value) (), v2.CONCAT2 (t2, _value) ())); \
   }
 
+#define DEFBINOP_SCALAR_FN(name, t1, t2, f)                             \
+  static octave_value                                                   \
+  CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
+                              const octave_base_value& a2)              \
+  {                                                                     \
+    const CONCAT2 (octave_, t1)& v1 = DYNORSTAT_CAST<const CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t2)& v2 = DYNORSTAT_CAST<const CONCAT2 (octave_, t2)&> (a2); \
+                                                                        \
+    return octave_value (                                               \
+      f (v1.CONCAT2 (octave_, t1)::CONCAT2 (t1, _value) (),             \
+         v2.CONCAT2 (octave_, t2)::CONCAT2 (t2, _value) ()));    \
+  }
+
 #define DEFNDBINOP_FN(name, t1, t2, e1, e2, f)                          \
   static octave_value                                                   \
   CONCAT2 (oct_binop_, name) (const octave_base_value& a1,              \
