Back to index

lightning-sunbird  0.9+nobinonly
xptcinvoke_arm.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* Platform specific code to invoke XPCOM methods on native objects */
00039 
00040 #include "xptcprivate.h"
00041 
00042 #if !defined(LINUX) || !defined(__arm__)
00043 #error "This code is for Linux ARM only. Check that it works on your system, too.\nBeware that this code is highly compiler dependent."
00044 #endif
00045 
00046 // Remember that these 'words' are 32bit DWORDS
00047 
00048 static PRUint32
00049 invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s)
00050 {
00051     PRUint32 result = 0;
00052     for(PRUint32 i = 0; i < paramCount; i++, s++)
00053     {
00054         if(s->IsPtrData())
00055         {
00056             result++;
00057             continue;
00058         }
00059         switch(s->type)
00060         {
00061         case nsXPTType::T_I8     :
00062         case nsXPTType::T_I16    :
00063         case nsXPTType::T_I32    :
00064             result++;
00065             break;
00066         case nsXPTType::T_I64    :
00067             result+=2;
00068             break;
00069         case nsXPTType::T_U8     :
00070         case nsXPTType::T_U16    :
00071         case nsXPTType::T_U32    :
00072             result++;
00073             break;
00074         case nsXPTType::T_U64    :
00075             result+=2;
00076             break;
00077         case nsXPTType::T_FLOAT  :
00078             result++;
00079             break;
00080         case nsXPTType::T_DOUBLE :
00081             result+=2;
00082             break;
00083         case nsXPTType::T_BOOL   :
00084         case nsXPTType::T_CHAR   :
00085         case nsXPTType::T_WCHAR  :
00086             result++;
00087             break;
00088         default:
00089             // all the others are plain pointer types
00090             result++;
00091             break;
00092         }
00093     }
00094     return result;
00095 }
00096 
00097 static void
00098 invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s)
00099 {
00100     for(PRUint32 i = 0; i < paramCount; i++, d++, s++)
00101     {
00102         if(s->IsPtrData())
00103         {
00104             *((void**)d) = s->ptr;
00105             continue;
00106         }
00107         switch(s->type)
00108         {
00109         case nsXPTType::T_I8     : *((PRInt8*)  d) = s->val.i8;          break;
00110         case nsXPTType::T_I16    : *((PRInt16*) d) = s->val.i16;         break;
00111         case nsXPTType::T_I32    : *((PRInt32*) d) = s->val.i32;         break;
00112         case nsXPTType::T_I64    : *((PRInt64*) d) = s->val.i64; d++;    break;
00113         case nsXPTType::T_U8     : *((PRUint8*) d) = s->val.u8;          break;
00114         case nsXPTType::T_U16    : *((PRUint16*)d) = s->val.u16;         break;
00115         case nsXPTType::T_U32    : *((PRUint32*)d) = s->val.u32;         break;
00116         case nsXPTType::T_U64    : *((PRUint64*)d) = s->val.u64; d++;    break;
00117         case nsXPTType::T_FLOAT  : *((float*)   d) = s->val.f;           break;
00118         case nsXPTType::T_DOUBLE : *((double*)  d) = s->val.d;   d++;    break;
00119         case nsXPTType::T_BOOL   : *((PRBool*)  d) = s->val.b;           break;
00120         case nsXPTType::T_CHAR   : *((char*)    d) = s->val.c;           break;
00121         case nsXPTType::T_WCHAR  : *((wchar_t*) d) = s->val.wc;          break;
00122         default:
00123             // all the others are plain pointer types
00124             *((void**)d) = s->val.p;
00125             break;
00126         }
00127     }
00128 }
00129 
00130 extern "C" {
00131     struct my_params_struct {
00132         nsISupports* that;      
00133         PRUint32 Index;         
00134         PRUint32 Count;         
00135         nsXPTCVariant* params;  
00136         PRUint32 fn_count;     
00137         PRUint32 fn_copy;      
00138     };
00139 }
00140 
00141 XPTC_PUBLIC_API(nsresult)
00142 XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
00143                    PRUint32 paramCount, nsXPTCVariant* params)
00144 {
00145     PRUint32 result;
00146     struct my_params_struct my_params;
00147     my_params.that = that;
00148     my_params.Index = methodIndex;
00149     my_params.Count = paramCount;
00150     my_params.params = params;
00151     my_params.fn_copy = (PRUint32) &invoke_copy_to_stack;
00152     my_params.fn_count = (PRUint32) &invoke_count_words;
00153 
00154 /* This is to call a given method of class that.
00155  * The parameters are in params, the number is in paramCount.
00156  * The routine will issue calls to count the number of words
00157  * required for argument passing and to copy the arguments to
00158  * the stack.
00159  * Since APCS passes the first 3 params in r1-r3, we need to
00160  * load the first three words from the stack and correct the stack
00161  * pointer (sp) in the appropriate way. This means:
00162  *
00163  * 1.) more than 3 arguments: load r1-r3, correct sp and remember No.
00164  *                         of bytes left on the stack in r4
00165  *
00166  * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope),
00167  *              restore sp as if nothing had happened and set the marker r4 to zero.
00168  *
00169  * Afterwards sp will be restored using the value in r4 (which is not a temporary register
00170  * and will be preserved by the function/method called according to APCS [ARM Procedure
00171  * Calling Standard]).
00172  *
00173  * !!! IMPORTANT !!!
00174  * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented
00175  * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])!
00176  *
00177  */
00178  
00179   __asm__ __volatile__(
00180     "ldr      r1, [%1, #12] \n\t"  /* prepare to call invoke_count_words     */
00181     "ldr      ip, [%1, #16] \n\t"  /* r0=paramCount, r1=params        */
00182     "ldr      r0, [%1,  #8] \n\t"
00183     "mov      lr, pc        \n\t"  /* call it...                      */
00184     "mov      pc, ip        \n\t"
00185     "mov      r4, r0, lsl #2       \n\t"  /* This is the amount of bytes needed.    */
00186     "sub      sp, sp, r4    \n\t"  /* use stack space for the args... */
00187     "mov      r0, sp        \n\t"  /* prepare a pointer an the stack  */
00188     "ldr      r1, [%1,  #8] \n\t"  /* =paramCount                            */
00189     "ldr      r2, [%1, #12] \n\t"  /* =params                         */
00190     "ldr      ip, [%1, #20] \n\t"  /* =invoke_copy_to_stack           */
00191     "mov      lr, pc        \n\t"  /* copy args to the stack like the */
00192     "mov      pc, ip        \n\t"  /* compiler would.                 */
00193     "ldr      r0, [%1]      \n\t"  /* =that                           */
00194     "ldr      r1, [r0, #0]  \n\t"  /* get that->vtable offset         */
00195     "ldr      r2, [%1, #4]  \n\t"
00196     "mov      r2, r2, lsl #2       \n\t"  /* a vtable_entry(x)=8 + (4 bytes * x)    */
00197 #if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */
00198     "ldr        ip, [r1, r2]    \n\t"   /* get method adress from vtable        */
00199 #else /* non G++ V3 ABI */
00200     "add      r2, r2, #8    \n\t"  /* with this compilers                    */
00201     "ldr      ip, [r1, r2]  \n\t"  /* get method adress from vtable   */
00202 #endif
00203     "cmp      r4, #12              \n\t"  /* more than 3 arguments???        */
00204     "ldmgtia  sp!, {r1, r2, r3}\n\t"      /* yes: load arguments for r1-r3   */
00205     "subgt    r4, r4, #12   \n\t"  /*      and correct the stack pointer     */
00206     "ldmleia  sp, {r1, r2, r3}\n\t"       /* no:  load r1-r3 from stack             */ 
00207     "addle    sp, sp, r4    \n\t"  /*      and restore stack pointer  */
00208     "movle    r4, #0        \n\t"  /*     a mark for restoring sp            */
00209     "ldr      r0, [%1, #0]  \n\t"  /* get (self)                      */
00210     "mov      lr, pc        \n\t"  /* call mathod                            */
00211     "mov      pc, ip        \n\t"
00212     "add      sp, sp, r4    \n\t"  /* restore stack pointer           */
00213     "mov      %0, r0        \n\t"  /* the result...                   */
00214     : "=r" (result)
00215     : "r" (&my_params)
00216     : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "sp"
00217     );
00218     
00219   return result;
00220 }