Add xptcall support for SH4 processors
authorMike Hommey <glandium@debian.org>
Fri, 30 Apr 2010 09:03:50 +0000 (11:03 +0200)
committerMike Hommey <glandium@debian.org>
Tue, 14 Feb 2023 23:45:08 +0000 (23:45 +0000)
Closes: #553593
https://bugzilla.mozilla.org/show_bug.cgi?id=382214

Gbp-Pq: Topic porting
Gbp-Pq: Name Add-xptcall-support-for-SH4-processors.patch

xpcom/reflect/xptcall/md/unix/moz.build
xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_sh.cpp [new file with mode: 0644]
xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_sh.cpp [new file with mode: 0644]

index 1779c148cb20a813900ef773bb5d347de97f959e..43a10a2291fa35adf3aea609a30fa1df0f3f4019 100644 (file)
@@ -262,6 +262,11 @@ if CONFIG["OS_ARCH"] == "Linux":
             CXXFLAGS += [
                 "-fno-integrated-as",
             ]
+    elif CONFIG['OS_TEST'] in ('sh4', 'sh4a'):
+        SOURCES += [
+            'xptcinvoke_linux_sh.cpp',
+            'xptcstubs_linux_sh.cpp',
+        ]
 
 if CONFIG["OS_ARCH"] == "Linux" and CONFIG["CPU_ARCH"] == "riscv64":
     SOURCES += [
diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_sh.cpp b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_sh.cpp
new file mode 100644 (file)
index 0000000..ca4807d
--- /dev/null
@@ -0,0 +1,203 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  - Copyright (C) 2008-2009 STMicroelectronics
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * Based on the neutroni port, however that assumed that the compiler was pushing params
+ * onto the stack. Change to take this into account.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "xptcprivate.h"
+
+extern "C" {
+
+const int c_int_register_params = 4;
+const int c_float_register_params = 8;
+
+static PRUint32 __attribute__((__used__))
+copy_to_stack(PRUint32 **that,PRUint32 methodIndex,PRUint32 paramCount, nsXPTCVariant* s,PRUint32* data)
+{
+       int intCount = 1; // Because of that
+       int floatCount = 0;
+       PRUint32 *intRegParams=data+1 ;
+       float  *floatRegParams = (float *)(data+4);
+
+       /* Push the that register into the right place so it can be restored on exit */
+       *data= (PRUint32)(that);
+       data+=12; /* 4 integer registers, and 8 floating point registers */
+
+       for ( PRUint32 i = 0; i < paramCount; ++i, ++s )
+       {
+               nsXPTType type = s->IsPtrData() ? nsXPTType::T_I32 : s->type;
+
+               switch ( type ) {
+                       case nsXPTType::T_I64:
+                       case nsXPTType::T_U64:
+                               // Space to pass in registers?
+                               if ( (c_int_register_params - intCount) >= 2 ) {
+                                       *((PRInt64 *) intRegParams) = s->val.i64;
+                                       intRegParams += 2;
+                                       intCount += 2;
+                               }
+                               else {
+                                       *((PRInt64*) data) = s->val.i64;
+                                       data += 2;
+                               }
+                               break;
+                       case nsXPTType::T_FLOAT:
+                               // Space to pass in registers?
+                               if ( floatCount < c_float_register_params ) {
+                                       *floatRegParams = s->val.f;
+                                       ++floatCount;
+                                       ++floatRegParams;
+                               }
+                               else {
+                                       *((float*) data) = s->val.f;
+                                       ++data;
+                               }
+                               break;
+                       case nsXPTType::T_DOUBLE:
+                               // Space to pass in registers?
+                               if ( (c_float_register_params - floatCount) >= 2  ) {
+                                       if ( (floatCount & 1) != 0 ) {
+                                               ++floatCount;
+                                               ++floatRegParams;
+                                       }
+                                       *(double *)floatRegParams = s->val.d;
+                                       floatCount += 2;
+                                       floatRegParams += 2;
+                               }
+                               else {
+                                       *((double *) data) = s->val.d;
+                                       data += 2;
+                               }
+                               break;
+                       default:                // 32 (non-float) value
+                               PRInt32 value = (PRInt32) (s->IsPtrData() ?  s->ptr : s->val.p);
+                               // Space to pass in registers?
+                               if ( intCount < c_int_register_params ) {
+                                       *intRegParams = value;
+                                       ++intRegParams;
+                                       ++intCount;
+                               }
+                               else {
+                                       *data = value;
+                                       ++data;
+                               }
+                               break;
+               }
+       }
+
+       /* Now calculate the return address
+        * Dereference that to get vtable pointer
+        */
+       return *( (*(that))+(methodIndex) );
+
+}
+
+}
+
+       /* This was originally done as a C function, but the original code was
+        * relying on how the compiler laid out the stack. Later versions of
+        * gcc do a better job of optimising and never push the parameters on the
+        * stack. So it is simpler to just write the whole thing in assembler anyway
+        */
+
+       /* Because the SH processor passes the first few parameters in registers
+          it is a bit tricky setting things up right.  To make things easier,
+          all the hard work will be done by copy_to_stack above.  We pass to it
+          a chunk of memory, the bottom of which will be copied to registers r4 to r7
+          and fr4 to fr11 before calling the target function.
+       */
+
+/* r4= that, r5=methodIndex,r6=paramCount,r7=params */
+
+ __asm__ (
+
+
+    /* Make space for parameters to be passed to the method.  Assume worst case
+       8 bytes per parameter.  Also leave space for 4 longs and 8 floats that
+       will be put into registers.  The worst case is all int64 parameters
+       and even in this case 8 bytes are passed in registers so we can
+       deduct this from our allocation.
+    */
+       ".section .text\n"
+       ".balign 4\n"
+       ".global NS_InvokeByIndex_P\n"
+       "NS_InvokeByIndex_P:\n"
+       "mov.l r14, @-r15 \n\t" // Push frame
+       "sts.l pr, @-r15 \n\t"  // Push link
+       "mov.l r8, @-r15 \n\t"  // Save
+       "mov  r15, r14\n\t"     // Set frame
+       "mov    #3, r1 \n\t"    // Assume worse case, all params are 64bit, hence *8
+       "mov    r6, r2\n\t"
+       "shld   r1, r2 \n\t"
+       "mov    r2, r8  \n\t"   // Save stack drop
+       "add    #48, r2 \n\t"   // Space for 4 longs, 8 floats
+       "sub    r2, r15 \n\t"   // Drop stack
+       "mov.l  1f, r1 \n\t"    // Get address of copy_to_stack_function
+       "jsr    @r1 \n\t"
+         "mov.l   r15, @-r15 \n\t"     //  Params will be dumped here
+       "add    #4, r15 \n\t"   // Pop stack ptr param. r0 contains method address
+
+       /* Now everything is laid out nicely in the stack.  We just have to
+          load values at the top end of the memory area into registers and
+          make the call.  We may load more things into registers than needed,
+          but nobody will care about that.
+       */
+
+       "mov.l  @r15+, r4 \n\t" // that
+       "mov.l  @r15+, r5 \n\t"
+       "mov.l  @r15+, r6 \n\t"
+       "mov.l  @r15+, r7 \n\t"
+       "fmov.s @r15+, fr5 \n\t"
+       "fmov.s @r15+, fr4 \n\t"
+       "fmov.s @r15+, fr7 \n\t"
+       "fmov.s @r15+, fr6 \n\t"
+       "fmov.s @r15+, fr9 \n\t"
+       "fmov.s @r15+, fr8 \n\t"
+       "fmov.s @r15+, fr11 \n\t"
+       "jsr    @r0 \n\t" // Invoke method
+         "fmov.s       @r15+, fr10 \n\t"
+       "add  r8, r15\n\t"              // Pop stack back
+       "mov.l @r15+, r8\n\t" // Restore r8
+       "lds.l @r15+, pr\n\t"
+       "rts\n\t"
+         "mov.l @r15+, r14\n\t"
+       ".balign 4\n\t"
+       "1: .long copy_to_stack \n\t"
+   );
+
diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_sh.cpp b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_sh.cpp
new file mode 100644 (file)
index 0000000..cf9fcea
--- /dev/null
@@ -0,0 +1,271 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  - Copyright (C) 2008-2009 STMicroelectronics
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * Based on the neutrino code, with some bug fixes and using the C preprocessor
+ * like all the other ports rather than the python script.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "xptcprivate.h"
+#include "xptiprivate.h"
+
+const int c_int_register_params = 3;
+const int c_float_register_params = 8;
+
+/*
+   Dispatch function for all stubs.
+
+   The parameters to the original function are spread between 'data' which
+   is value of the stack pointer when the stub was called, intRegParams which
+   points to an area containing the values of r5, r6 and r7 when the stub was
+   called and floatRegParams which points to an area containing the values
+   of float registers fr4 to fr11 when the stub was called.
+
+ */
+extern "C" nsresult
+PrepareAndDispatch(nsXPTCStubBase* self, int methodIndex, PRUint32* data,
+                                  PRUint32 *intRegParams, float *floatRegParams)
+{
+#define PARAM_BUFFER_COUNT     16
+
+       nsresult result = NS_ERROR_FAILURE;
+       int intCount = 0;
+       int floatCount = 0;
+       nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
+       nsXPTCMiniVariant* dispatchParams = NULL;
+       const nsXPTMethodInfo* info;
+       PRUint8 paramCount;
+       PRUint8 i;
+
+       NS_ASSERTION(self,"no self");
+
+       self->mEntry->GetMethodInfo(PRUint16(methodIndex), &info);
+       NS_ASSERTION(info,"no interface info");
+
+       paramCount = info->GetParamCount();
+
+       // setup variant array pointer
+       if(paramCount > PARAM_BUFFER_COUNT)
+               dispatchParams = new nsXPTCMiniVariant[paramCount];
+       else
+               dispatchParams = paramBuffer;
+       NS_ASSERTION(dispatchParams,"no place for params");
+
+       for ( i = 0; i < paramCount; ++i ) {
+               const nsXPTParamInfo& param = info->GetParam(i);
+               nsXPTCMiniVariant* dp = &dispatchParams[i];
+               nsXPTType type = param.IsOut() ? nsXPTType::T_I32 : param.GetType();
+
+               switch ( type ) {
+                       case nsXPTType::T_I64:
+                       case nsXPTType::T_U64:
+                               // Was this passed  in a register?
+                               if ( (c_int_register_params - intCount) >= 2 ) {
+                                       dp->val.i64 = *((PRInt64 *) intRegParams);
+                                       intRegParams += 2;
+                                       intCount += 2;
+                               }
+                               else {
+                                       dp->val.i64 = *((PRInt64*) data);
+                                       data += 2;
+                               }
+                               break;
+                       case nsXPTType::T_FLOAT:
+                               // Was this passed  in a register?
+                               if ( floatCount < c_float_register_params ) {
+                                       dp->val.f = *floatRegParams;
+                                       ++floatCount;
+                                       ++floatRegParams;
+                               }
+                               else {
+                                       dp->val.f = *((float*) data);
+                                       ++data;
+                               }
+                               break;
+                       case nsXPTType::T_DOUBLE:
+                               // Was this passed  in a register?
+                               if ( (c_float_register_params - floatCount) >= 2  ) {
+                                       if ( floatCount & 1 != 0 ) {
+                                               ++floatCount;
+                                               ++floatRegParams;
+                                       }
+                                       dp->val.d = *(double *)floatRegParams;
+                                       floatCount += 2;
+                                       floatRegParams += 2;
+                               }
+                               else {
+                                       dp->val.d = *((double *) data);
+                                       data += 2;
+                               }
+                               break;
+                       default:                // 32-bit (non-float) value
+                               // Was this passed  in a register?
+                               if ( intCount < c_int_register_params ) {
+                                       dp->val.i32 = *intRegParams;
+                                       ++intRegParams;
+                                       ++intCount;
+                               }
+                               else {
+                                       dp->val.i32 = *data;
+                                       ++data;
+                               }
+                               break;
+               }
+       }
+
+       result = self->mOuter->CallMethod((PRUint16)methodIndex, info, dispatchParams);
+
+       if(dispatchParams != paramBuffer)
+               delete [] dispatchParams;
+
+       return result;
+}
+
+
+__asm__ (
+       ".text\n"
+       ".little\n"
+       ".section       .rodata\n"
+
+       ".globl SharedStub\n"
+       ".type  SharedStub, @function\n"
+       "SharedStub:\n"
+       "mov       r15, r1\n"
+       "mov.l  r14,@-r15\n"
+       "sts.l  pr,@-r15\n"
+       "mov            r15, r14\n"
+
+       /* Some parameters might have been passed in registers, so push them
+        * all onto the stack, PrepareAndDispatch can then work out whats what
+        * given method type information.
+        */
+       "mov.l r7, @-r15\n"
+       "mov.l r6, @-r15\n"
+       "mov.l r5, @-r15\n"
+       "mov      r15, r7\n"    /* r7 = PrepareAndDispatch intRegParams param   */
+
+       "fmov.s fr10, @-r15\n"
+       "fmov.s fr11, @-r15\n"
+       "fmov.s fr8, @-r15\n"
+       "fmov.s fr9, @-r15\n"
+       "fmov.s fr6, @-r15\n"
+       "fmov.s fr7, @-r15\n"
+       "fmov.s fr4, @-r15\n"
+       "fmov.s fr5, @-r15\n"
+       "mov.l  r15, @-r15\n"   /* PrepareAndDispatch floatRegParams param              */
+
+       "mov       r1, r6\n"    /* r6 = PrepareAndDispatch data param                   */
+
+       "mov.l  1f, r1\n"
+       "jsr       @r1\n"               /* Note, following instruction is executed first*/
+         "mov     r2, r5\n"            /* r5 = PrepareAndDispatch methodIndex param    */
+
+       "mov            r14,r15\n"
+       "lds.l  @r15+,pr\n"
+       "mov.l  @r15+,r14\n"
+       "rts\n"
+         "nop\n"
+       ".align 2\n"
+       "1:\n"
+       ".long  PrepareAndDispatch\n"
+       );
+
+#define STUB_ENTRY(n)                                          \
+__asm__(                                                       \
+       ".text\n"                                               \
+       ".align 1 \n"                                           \
+       ".if        " #n " < 10\n\t"                            \
+       ".globl    _ZN14nsXPTCStubBase5Stub" #n "Ev\n\t"        \
+       ".type     _ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n"\
+       "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t"                 \
+       ".elseif    " #n " < 100\n\t"                           \
+       ".globl    _ZN14nsXPTCStubBase6Stub" #n "Ev\n\t"        \
+       ".type     _ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n"\
+       "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t"                 \
+       ".elseif    " #n " < 1000\n\t"                          \
+       ".globl    _ZN14nsXPTCStubBase7Stub" #n "Ev\n\t"        \
+       ".type     _ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n"\
+       "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t"                 \
+       ".else\n\t"                                             \
+       ".err       \"stub number " #n " >= 1000 not yet supported\"\n\t" \
+       ".endif\n\t"                                            \
+       "mov.l  1f, r1 \n"                                      \
+       ".if "#n" < 128 \n"                                     \
+       "jmp @r1 \n"                                            \
+       "  mov #"#n",r2 \n"                                     \
+       ".elseif "#n" < 256 \n"                                 \
+       "mov #"#n", r2 \n"                                      \
+       "jmp @r1 \n"                                            \
+       "  extu.b r2, r2 \n"                                    \
+       ".else \n"                                              \
+       "mov #"#n" & 0xff,r2 \n"                                \
+       "extu.b r2, r2 \n"                                      \
+       "mov #"#n">>8, r3 \n"                                   \
+       "shll8  r3 \n"                                          \
+       "jmp @r1 \n"                                            \
+       "  or r3, r2 \n"                                        \
+       ".endif \n"                                             \
+       ".if "#n" % 20 == 0\n"                                  \
+       ".align 2\n"                                            \
+       "1:\n"                                                  \
+       ".long SharedStub\n"                                    \
+       ".endif\n"                                              \
+       );
+
+
+/* Due to the fact that the SH4 can only load forward labels, we have
+ * to use sentinel_entry to output the last label. A better solution
+ * would be to introduce a STUB_LAST macro in the defs.in file, but
+ * this will do for now
+ */
+
+#define SENTINEL_ENTRY(n)              \
+__asm__(                               \
+".if "#n" == 0  \n"                    \
+       ".text \n"                      \
+       ".align 2\n"                    \
+       "1:\n"                          \
+       ".long SharedStub\n"            \
+".endif\n"                             \
+);                                     \
+                                       \
+nsresult nsXPTCStubBase::Sentinel##n()  \
+{ \
+       NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \
+       return NS_ERROR_NOT_IMPLEMENTED; \
+}
+
+#include "xptcstubsdef.inc"