Back to index

lightning-sunbird  0.9+nobinonly
xptcinvoke_nto_shle.cpp
Go to the documentation of this file.
00001 #include "xptcprivate.h"
00002 
00003 extern "C" {
00004 
00005 const int c_int_register_params = 3;
00006 const int c_float_register_params = 8;
00007 
00008 static void
00009 copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, int size, PRUint32* data)
00010 {
00011        int intCount = 0;
00012        int floatCount = 0;
00013        PRUint32 *intRegParams = data + (size / sizeof(PRUint32)) - c_int_register_params;
00014        float  *floatRegParams = (float *)intRegParams - c_float_register_params;
00015 
00016     for ( PRUint32 i = 0; i < paramCount; ++i, ++s )
00017     {
00018               nsXPTType type = s->IsPtrData() ? nsXPTType::T_I32 : s->type;
00019 
00020               switch ( type ) {
00021         case nsXPTType::T_I64:
00022         case nsXPTType::T_U64:
00023                      // Space to pass in registers?
00024                      if ( (c_int_register_params - intCount) >= 2 ) {
00025                             *((PRInt64 *) intRegParams) = s->val.i64;
00026                             intRegParams += 2;
00027                             intCount += 2;
00028                      }
00029                      else {
00030                             *((PRInt64*) data) = s->val.i64;
00031                             data += 2;
00032                      }
00033                      break;
00034         case nsXPTType::T_FLOAT:
00035                      // Space to pass in registers?
00036                      if ( floatCount < c_float_register_params ) {
00037                             *floatRegParams = s->val.f;
00038                             ++floatCount;
00039                             ++floatRegParams;
00040                      }
00041                      else {
00042                             *((float*) data) = s->val.f;
00043                             ++data;
00044                      }                    
00045                      break;
00046         case nsXPTType::T_DOUBLE:
00047                      // Space to pass in registers?
00048                      if ( (c_float_register_params - floatCount) >= 2  ) {
00049                             if ( (floatCount & 1) != 0 ) {
00050                                    ++floatCount;
00051                                    ++floatRegParams;                                
00052                             }
00053                             *(double *)floatRegParams = s->val.d;
00054                             floatCount += 2;
00055                             floatRegParams += 2;
00056                      }
00057                      else {
00058                             *((double *) data) = s->val.d;
00059                             data += 2;
00060                      }                    
00061                      break;
00062               default:             // 32 (non-float) value
00063                      PRInt32 value = (PRInt32) (s->IsPtrData() ?  s->ptr : s->val.p);
00064                      // Space to pass in registers?
00065                      if ( intCount < c_int_register_params ) {
00066                             *intRegParams = value;
00067                             ++intRegParams;
00068                             ++intCount;
00069                      }
00070                      else {
00071                             *data = value;
00072                             ++data;
00073                      }
00074                      break;
00075         }
00076     }  
00077 }
00078 
00079 XPTC_PUBLIC_API(nsresult)
00080 XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
00081                    PRUint32 paramCount, nsXPTCVariant* params)
00082 {
00083 #ifdef __GNUC__            /* Gnu compiler. */
00084        int result;
00085        void (*fn_copy) (PRUint32 paramCount, nsXPTCVariant* s, int size, PRUint32* d) = copy_to_stack;
00086 
00087        /* Because the SH processor passes the first few parameters in registers
00088           it is a bit tricky setting things up right.  To make things easier,
00089           all the hard work will be done by copy_to_stack above.  We pass to it
00090           a chunk of memory, the top of which will be copied to registers r5 to r7
00091           and fr4 to fr11 before calling the target function.
00092        */
00093 
00094  __asm__ __volatile__(
00095     /* Make space for parameters to be passed to the method.  Assume worst case 
00096           8 bytes per parameter.  Also leave space for 3 longs and 8 floats that
00097           will be put into registers.  The worst case is all int64 parameters
00098           and even in this case 8 bytes are passed in registers so we can
00099           deduct this from our allocation.
00100        */
00101        "mov.l @(8,r14), r4 \n\t"   // copy_to_stack paramCount parameter
00102        "mov   r4, r6 \n\t"
00103        "mov   #3, r1 \n\t"
00104        "shld  r1, r6 \n\t"
00105        "add   #36, r6 \n\t"        // Space for 3 longs, 8 floats - 8 bytes
00106        "sub   r6, r15 \n\t"
00107        "mov   r15, r7 \n\t"
00108        "mov.l @(20,r14), r1 \n\t"  // fn_copy
00109        "jsr   @r1 \n\t"                   // Note, next instruction is executed first
00110        "mov.l @(12,r14), r5 \n\t"  // copy_to_stack data parameter
00111 
00112        /* Now everything is laid out nicely in the stack.  We just have to
00113           load values at the top end of the memory area into registers and
00114           make the call.  We may load more things into registers than needed,
00115           but nobody will care about that.
00116        */     
00117        "mov   r14, r1 \n\t"
00118        "add   #-44, r1 \n\t"
00119        "fmov.s       @r1+, fr5 \n\t"
00120        "fmov.s       @r1+, fr4 \n\t"
00121        "fmov.s       @r1+, fr7 \n\t"
00122        "fmov.s       @r1+, fr6 \n\t"
00123        "fmov.s       @r1+, fr9 \n\t"
00124        "fmov.s       @r1+, fr8 \n\t"
00125        "fmov.s       @r1+, fr11 \n\t"
00126        "fmov.s       @r1+, fr10 \n\t"
00127        "mov.l @r1+, r5 \n\t"
00128        "mov.l @r1+, r6 \n\t"
00129        "mov.l @r1+, r7 \n\t"       
00130        "mov.l @r14, r1 \n\t"              // that -> r1
00131        "mov.l @r1, r1 \n\t"        // vtbl -> r1
00132        "mov.l @(4,r14), r4 \n\t"   // methodIndex -> r4
00133        "shll2 r4     \n\t"
00134        "add   r4, r1 \n\t"
00135        "mov.l @r1, r1 \n\t"        // method addr -> r1
00136        "jsr   @r1 \n\t"
00137        "mov.l @r14, r4 \n\t"              // that -> r4  (note, executed before jsr)
00138        "mov.l r0, @(16,r14) \n\r"  // Save return value in result
00139     : : : "r1", "r4", "r6", "r7", "pr", "dr4", "dr6", "dr8"
00140    );
00141     
00142   return result;
00143 
00144 #else
00145 #error "can't find a compiler to use"
00146 #endif /* __GNUC__ */
00147 
00148 }
00149 
00150 }