changeset 611:d94b053311a7

test/plain_c++: - refactored to share code - extended to treat default this calls and explicitly as cdecl declared ones, separately - prev point fixes implicitly on x86 a wrong dcMode setting (assumed that cdecl for methods would default to the native this call convention, but actually does not, applies cdecl verbatim) - extended aggr tests to also test explicit cdecl as well as MS thiscalls on x86 - simplified
author Tassilo Philipp
date Thu, 29 Sep 2022 11:47:54 +0200
parents fea865cd1305
children 086362f4ae3f
files test/plain_c++/test_main.cc
diffstat 1 files changed, 114 insertions(+), 147 deletions(-) [+]
line wrap: on
line diff
--- a/test/plain_c++/test_main.cc	Thu Sep 29 10:51:24 2022 +0200
+++ b/test/plain_c++/test_main.cc	Thu Sep 29 11:47:54 2022 +0200
@@ -46,27 +46,6 @@
 
 
 /* -------------------------------------------------------------------------
- * test: identity function calls
- * ------------------------------------------------------------------------- */
-
-#define DEF_FUNCS(API,NAME) \
-void       API fun_##NAME##_v()             {           } \
-DCbool     API fun_##NAME##_b(DCbool x)     { return x; } \
-DCint      API fun_##NAME##_i(DCint x)      { return x; } \
-DClong     API fun_##NAME##_j(DClong x)     { return x; } \
-DClonglong API fun_##NAME##_l(DClonglong x) { return x; } \
-DCfloat    API fun_##NAME##_f(DCfloat x)    { return x; } \
-DCdouble   API fun_##NAME##_d(DCdouble x)   { return x; } \
-DCpointer  API fun_##NAME##_p(DCpointer  x) { return x; }
-
-/* __cdecl */
-
-#if !defined(DC__OS_Win32)
-#  define __cdecl
-#endif
-
-
-/* -------------------------------------------------------------------------
  * test: identity this calls
  * ------------------------------------------------------------------------- */
 
@@ -81,12 +60,10 @@
   DCpointer  p;
 };
 
-/* C++ class using __cdecl this call */
-
-// #define VTBI_DESTRUCTOR 0
 
 /*
- * the layout of the VTable is non-standard and it is not clear what is the initial real first method index.
+ * the layout of the VTable is non-standard and it is not clear what is the
+ * initial real first method index.
  * so far it turns out, *iff* dtor is defined, that:
  * on msvc/x86  : 1
  * on msvc/x64  : 1
@@ -119,32 +96,44 @@
 #define VTBI_GET_POINTER VTBI_BASE+13
 #define VTBI_SUM_3_INTS VTBI_BASE+14
 
-class Value
-{
-public:
-  virtual ~Value()   {}
+#define TEST_CLASS(NAME, CCONV) \
+class NAME \
+{ \
+public: \
+  virtual                  ~NAME()                   { } \
+ \
+  virtual void       CCONV setBool(DCbool x)         { mValue.B = x; } \
+  virtual DCbool     CCONV getBool()                 { return mValue.B; } \
+  virtual void       CCONV setInt(DCint x)           { mValue.i = x; } \
+  virtual DCint      CCONV getInt()                  { return mValue.i; } \
+  virtual void       CCONV setLong(DClong x)         { mValue.j = x; } \
+  virtual DClong     CCONV getLong()                 { return mValue.j; } \
+  virtual void       CCONV setLongLong(DClonglong x) { mValue.l = x; } \
+  virtual DClonglong CCONV getLongLong()             { return mValue.l; } \
+  virtual void       CCONV setFloat(DCfloat x)       { mValue.f = x; } \
+  virtual DCfloat    CCONV getFloat()                { return mValue.f; } \
+  virtual void       CCONV setDouble(DCdouble x)     { mValue.d = x; } \
+  virtual DCdouble   CCONV getDouble()               { return mValue.d; } \
+  virtual void       CCONV setPtr(DCpointer x)       { mValue.p = x; } \
+  virtual DCpointer  CCONV getPtr()                  { return mValue.p; } \
+ \
+  /* ellipsis test w/ this ptr */ \
+  virtual int        CCONV sum3Ints(DCint x, ...)    { va_list va; va_start(va,x); x += va_arg(va,int); x += va_arg(va,int); va_end(va); return x; } \
+ \
+private: \
+  ValueUnion mValue; \
+};
 
-  virtual void       __cdecl setBool(DCbool x)         { mValue.B = x; }
-  virtual DCbool     __cdecl getBool()                 { return mValue.B; }
-  virtual void       __cdecl setInt(DCint x)           { mValue.i = x; }
-  virtual DCint      __cdecl getInt()                  { return mValue.i; }
-  virtual void       __cdecl setLong(DClong x)         { mValue.j = x; }
-  virtual DClong     __cdecl getLong()                 { return mValue.j; }
-  virtual void       __cdecl setLongLong(DClonglong x) { mValue.l = x; }
-  virtual DClonglong __cdecl getLongLong()             { return mValue.l; }
-  virtual void       __cdecl setFloat(DCfloat x)       { mValue.f = x; }
-  virtual DCfloat    __cdecl getFloat()                { return mValue.f; }
-  virtual void       __cdecl setDouble(DCdouble x)     { mValue.d = x; }
-  virtual DCdouble   __cdecl getDouble()               { return mValue.d; }
-  virtual void       __cdecl setPtr(DCpointer x)       { mValue.p = x; }
-  virtual DCpointer  __cdecl getPtr()                  { return mValue.p; }
+TEST_CLASS(ValueThisDef, /*empty/default*/) /* default */
+#if defined(DC__Arch_Intel_x86)
+TEST_CLASS(ValueThisCdecl, __cdecl)         /* methods explicitly declared as cdecl */
+#if defined(DC__OS_Win32) && defined(DC__C_MSVC)
+TEST_CLASS(ValueThisMS, /*empty/default*/)  /* microsoft this call */
+#endif
+#endif
 
-  /* ellipsis test w/ this ptr */
-  virtual int        __cdecl sum3Ints(DCint x, ...)    { va_list va; va_start(va,x); x += va_arg(va,int); x += va_arg(va,int); va_end(va); return x; }
 
-private:
-  ValueUnion mValue;
-};
+
 
 template<typename T>
 bool testCallValue(DCCallVM* pc, const char* name)
@@ -268,60 +257,17 @@
 }
 
 
-#if defined(DC__OS_Win32) && defined(DC__C_MSVC)
-
-/* C++ class using (on win32: microsoft) this call */
-
-class ValueMS
-{
-public:
-  virtual ~ValueMS()    {}
-
-  virtual void       setBool(DCbool x)         { mValue.B = x; }
-  virtual DCbool     getBool()                 { return mValue.B; }
-  virtual void       setInt(DCint x)           { mValue.i = x; }
-  virtual DCint      getInt()                  { return mValue.i; }
-  virtual void       setLong(DClong x)         { mValue.j = x; }
-  virtual DClong     getLong()                 { return mValue.j; }
-  virtual void       setLongLong(DClonglong x) { mValue.l = x; }
-  virtual DClonglong getLongLong()             { return mValue.l; }
-  virtual void       setFloat(DCfloat x)       { mValue.f = x; }
-  virtual DCfloat    getFloat()                { return mValue.f; }
-  virtual void       setDouble(DCdouble x)     { mValue.d = x; }
-  virtual DCdouble   getDouble()               { return mValue.d; }
-  virtual void       setPtr(DCpointer x)       { mValue.p = x; }
-  virtual DCpointer  getPtr()                  { return mValue.p; }
-private:
-  ValueUnion mValue;
-};
-
-static bool testCallThisMS()
+template<class T>
+static bool testCallThis(DCint mode, const char* str)
 {
   bool r = false;
   DCCallVM* pc = dcNewCallVM(4096);
-  dcMode(pc, DC_CALL_C_X86_WIN32_THIS_MS);
+  dcMode(pc, mode);
   dcReset(pc);
   if(setjmp(jbuf) != 0)
     printf("sigsegv\n"), r=false;
   else
-    r = testCallValue<ValueMS>(pc, "MS");
-  dcFree(pc);
-  return r;
-}
-
-#endif
-
-
-static bool testCallThisC()
-{
-  bool r = false;
-  DCCallVM* pc = dcNewCallVM(4096);
-  dcMode(pc, DC_CALL_C_DEFAULT_THIS);
-  dcReset(pc);
-  if(setjmp(jbuf) != 0)
-    printf("sigsegv\n"), r=false;
-  else
-    r = testCallValue<Value>(pc, "c");
+    r = testCallValue<T>(pc, str);
   dcFree(pc);
   return r;
 }
@@ -329,65 +275,76 @@
 
 #if defined(DC__Feature_AggrByVal)
 
-class ValueAggr
-{
-public:
-  struct S { int i, j, k, l, m; };
-
-  virtual ~ValueAggr()    {}
-
-  virtual void  __cdecl setAggr(S x)  { mS.i = x.i; mS.j = x.j; mS.k = x.k; mS.l = x.l; mS.m = x.m; }
-  virtual S     __cdecl getAggr()     { return mS; }
-
-  /* ellipsis test w/ this ptr and big (!) aggregate return */
-  struct Big { int sum; long long dummy[50]; /*dummy to make it not fit in any regs*/ };
-  virtual struct Big  __cdecl sum3RetAggr(DCint x, ...) { va_list va; va_start(va,x); struct Big r = { x + va_arg(va,int) + va_arg(va,int) }; va_end(va); return r; }
+#define TEST_CLASS_AGGR(NAME, CCONV) \
+class NAME \
+{ \
+public: \
+  struct S { int i, j, k, l, m; }; \
+ \
+  virtual             ~NAME()       { } \
+ \
+  virtual void  CCONV setAggr(S x)  { mS.i = x.i; mS.j = x.j; mS.k = x.k; mS.l = x.l; mS.m = x.m; } \
+  virtual S     CCONV getAggr()     { return mS; } \
+ \
+  /* ellipsis test w/ this ptr and big (!) aggregate return */ \
+  struct Big { int sum; long long dummy[50]; /*dummy to make it not fit in any regs*/ }; \
+  virtual struct Big  CCONV sum3RetAggr(DCint x, ...) { va_list va; va_start(va,x); struct Big r = { x + va_arg(va,int) + va_arg(va,int) }; va_end(va); return r; } \
+ \
+  /* non-trivial aggregate */ \
+  struct NonTriv { \
+    int i, j; \
+    NonTriv(int a, int b) : i(a),j(b) { } \
+    NonTriv(const NonTriv& rhs) { static int a=13, b=37; i = a++; j = b++; } \
+  }; \
+  /* by value, so on first invocation a = 13,37, b = 14,38 and retval = 13*14,37*38, no matter the contents of the instances as copy ctor is called */ \
+  /* NOTE: copy of return value is subject to C++ "copy elision", so it is *not* calling the copy ctor for the return value */ \
+  virtual struct NonTriv  CCONV squareFields(NonTriv a, NonTriv b) { return NonTriv(a.i*b.i, a.j*b.j); } \
+ \
+private: \
+  struct S mS; \
+};
 
-  /* non-trivial aggregate */
-  struct NonTriv {
-    int i, j;
-    NonTriv(int a, int b) : i(a),j(b) { }
-    NonTriv(const NonTriv& rhs) { static int a=13, b=37; i = a++; j = b++; }
-  };
-  /* by value, so on first invocation a = 13,37, b = 14,38 and retval = 13*14,37*38, no matter the contents of the instances as copy ctor is called */
-  /* NOTE: copy of return value is subject to C++ "copy elision", so it is *not* calling the copy ctor for the return value */
-  virtual struct NonTriv  __cdecl squareFields(NonTriv a, NonTriv b) { return NonTriv(a.i*b.i, a.j*b.j); }
+TEST_CLASS_AGGR(ValueAggrThisDef, /*empty/default*/) /* default */
+#if defined(DC__Arch_Intel_x86)
+TEST_CLASS_AGGR(ValueAggrThisCdecl, __cdecl)         /* methods explicitly declared as cdecl */
+#if defined(DC__OS_Win32) && defined(DC__C_MSVC)
+TEST_CLASS_AGGR(ValueAggrThisMS, /*empty/default*/)  /* microsoft this call */
+#endif
+#endif
 
-private:
-  struct S mS;
-};
 
 #if (__cplusplus >= 201103L)
 #  include <type_traits>
 #endif
 
 /* special case w/ e.g. MS x64 C++ calling cconf: struct return ptr is passed as *2nd* arg */
-static bool testCallThisAggr()
+template<class T>
+static bool testCallThisAggr(DCint mode, const char* str)
 {
   bool r = false;
   DCCallVM* pc = dcNewCallVM(4096);
-  dcMode(pc, DC_CALL_C_DEFAULT_THIS);
+  dcMode(pc, mode);
 
   if(setjmp(jbuf) != 0)
     printf("sigsegv\n"), r=false;
   else
   {
-    ValueAggr o;
+    T o;
 
     DCpointer* vtbl =  *( (DCpointer**) &o ); /* vtbl is located at beginning of class */
-    ValueAggr::S st = { 124, -12, 434, 20202, -99999 }, returned;
+    typename T::S st = { 124, -12, 434, 20202, -99999 }, returned;
 
 #if (__cplusplus >= 201103L)
-    bool istriv = std::is_trivial<ValueAggr::S>::value;
+    bool istriv = std::is_trivial<typename T::S>::value;
 #else
     bool istriv = true; /* own deduction as no type trait */
 #endif
-    DCaggr *s = dcNewAggr(5, sizeof(ValueAggr::S));
-    dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, i), 1);
-    dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, j), 1);
-    dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, k), 1);
-    dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, l), 1);
-    dcAggrField(s, DC_SIGCHAR_INT, offsetof(ValueAggr::S, m), 1);
+    DCaggr *s = dcNewAggr(5, sizeof(typename T::S));
+    dcAggrField(s, DC_SIGCHAR_INT, offsetof(typename T::S, i), 1);
+    dcAggrField(s, DC_SIGCHAR_INT, offsetof(typename T::S, j), 1);
+    dcAggrField(s, DC_SIGCHAR_INT, offsetof(typename T::S, k), 1);
+    dcAggrField(s, DC_SIGCHAR_INT, offsetof(typename T::S, l), 1);
+    dcAggrField(s, DC_SIGCHAR_INT, offsetof(typename T::S, m), 1);
     dcCloseAggr(s);
 
     // set S::mS
@@ -405,7 +362,7 @@
     dcFreeAggr(s);
 
     r = returned.i == st.i && returned.j == st.j && returned.k == st.k && returned.l == st.l && returned.m == st.m && istriv;
-    printf("r:{iiiii}  (this/trivial): %d\n", r);
+    printf("r:{iiiii}  (%s/trivial): %d\n", str, r);
 
 
 
@@ -416,16 +373,16 @@
      * DC_CALL_C_ELLIPSIS_VARARGS (test is useful on win64 where thisptr is
      * passed *after* return aggregate's hidden ptr) */
 #if (__cplusplus >= 201103L)
-    istriv = std::is_trivial<ValueAggr::Big>::value;
+    istriv = std::is_trivial<typename T::Big>::value;
 #else
     istriv = true; /* own deduction as no type trait */
 #endif
-    s = dcNewAggr(2, sizeof(struct ValueAggr::Big));
-    dcAggrField(s, DC_SIGCHAR_INT, offsetof(struct ValueAggr::Big, sum), 1);
-    dcAggrField(s, DC_SIGCHAR_LONGLONG, offsetof(struct ValueAggr::Big, dummy), 50);
+    s = dcNewAggr(2, sizeof(struct T::Big));
+    dcAggrField(s, DC_SIGCHAR_INT, offsetof(struct T::Big, sum), 1);
+    dcAggrField(s, DC_SIGCHAR_LONGLONG, offsetof(struct T::Big, dummy), 50);
     dcCloseAggr(s);
     dcReset(pc);
-    dcMode(pc, DC_CALL_C_DEFAULT_THIS); /* <-- needed on x64/win64 */
+    dcMode(pc, mode);
 
     dcBeginCallAggr(pc, s);
     dcArgPointer(pc, &o);
@@ -434,34 +391,34 @@
     dcMode(pc, DC_CALL_C_ELLIPSIS_VARARGS);
     dcArgInt(pc, -157);
     dcArgInt(pc, 888);
-    struct ValueAggr::Big big;
+    struct T::Big big;
     dcCallAggr(pc, vtbl[VTBI_BASE+2], s, &big);
 
     dcFreeAggr(s);
 
     bool b = (big.sum == 820) && istriv;
     r = r && b;
-    printf("r:{il[50]}  (this/trivial/ellipsis): %d\n", b);
+    printf("r:{il[50]}  (%s/trivial/ellipsis): %d\n", str, b);
 
 
 
     /* non-trivial test ----------------------------------------------------------- */
 
 #if (__cplusplus >= 201103L)
-    istriv = std::is_trivial<ValueAggr::NonTriv>::value;
+    istriv = std::is_trivial<typename T::NonTriv>::value;
 #else
     istriv = false; /* own deduction as no type trait */
 #endif
     dcReset(pc);
-    dcMode(pc, DC_CALL_C_DEFAULT_THIS);
+    dcMode(pc, mode);
 
     /* non trivial aggregates: pass NULL for DCaggr* and do copy on our own (see doc) */
     dcBeginCallAggr(pc, NULL);
 
-    ValueAggr::NonTriv nt0(5, 6), nt1(7, 8), ntr(0, 0);
+    typename T::NonTriv nt0(5, 6), nt1(7, 8), ntr(0, 0);
     dcArgAggr(pc, NULL, &o); // this ptr
     /* make *own* copies, as dyncall cannot know how to call copy ctor */ //@@@ put into doc
-    ValueAggr::NonTriv nt0_ = nt0, nt1_ = nt1;
+    typename T::NonTriv nt0_ = nt0, nt1_ = nt1;
     dcArgAggr(pc, NULL, &nt0_); /* use *own* copy */
     dcArgAggr(pc, NULL, &nt1_); /* use *own* copy */
 
@@ -470,7 +427,7 @@
 
     b = ntr.i == 13*14 && ntr.j == 37*38 && !istriv;
     r = r && b;
-    printf("r:{ii}  (this/nontrivial/retval_copy_elision): %d\n", b);
+    printf("r:{ii}  (%s/nontrivial/retval_copy_elision): %d\n", str, b);
   }
 
   dcFree(pc);
@@ -490,12 +447,22 @@
 
   bool r = true;
 
-  r = testCallThisC() && r;
+  r = testCallThis<ValueThisDef>(DC_CALL_C_DEFAULT_THIS, "thisDef") && r;
+#if defined(DC__Arch_Intel_x86)
+  r = testCallThis<ValueThisCdecl>(DC_CALL_C_X86_CDECL, "thisCdecl") && r;
 #if defined(DC__OS_Win32) && defined(DC__C_MSVC)
-  r = testCallThisMS() && r;
+  r = testCallThis<ValueThisMS>(DC_CALL_C_X86_WIN32_THIS_MS, "thisMS") && r;
+#endif
 #endif
+
 #if defined(DC__Feature_AggrByVal)
-  r = testCallThisAggr() && r;
+  r = testCallThisAggr<ValueAggrThisDef>(DC_CALL_C_DEFAULT_THIS, "thisDef") && r;
+#if defined(DC__Arch_Intel_x86)
+  r = testCallThisAggr<ValueAggrThisCdecl>(DC_CALL_C_X86_CDECL, "thisCdecl") && r;
+#if defined(DC__OS_Win32) && defined(DC__C_MSVC)
+  r = testCallThisAggr<ValueAggrThisMS>(DC_CALL_C_X86_WIN32_THIS_MS, "thisMS") && r;
+#endif
+#endif
 #endif
 
   printf("result: plain_c++: %d\n", r);