Back to index

lightning-sunbird  0.9+nobinonly
xptcinvoke_arm_openbsd.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 // Remember that these 'words' are 32bit DWORDS
00043 
00044 static PRUint32
00045 invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s)
00046 {
00047     PRUint32 result = 0;
00048     for(PRUint32 i = 0; i < paramCount; i++, s++)
00049     {
00050         if(s->IsPtrData())
00051         {
00052             result++;
00053             continue;
00054         }
00055         switch(s->type)
00056         {
00057         case nsXPTType::T_I8     :
00058         case nsXPTType::T_I16    :
00059         case nsXPTType::T_I32    :
00060             result++;
00061             break;
00062         case nsXPTType::T_I64    :
00063             result+=2;
00064             break;
00065         case nsXPTType::T_U8     :
00066         case nsXPTType::T_U16    :
00067         case nsXPTType::T_U32    :
00068             result++;
00069             break;
00070         case nsXPTType::T_U64    :
00071             result+=2;
00072             break;
00073         case nsXPTType::T_FLOAT  :
00074             result++;
00075             break;
00076         case nsXPTType::T_DOUBLE :
00077             result+=2;
00078             break;
00079         case nsXPTType::T_BOOL   :
00080         case nsXPTType::T_CHAR   :
00081         case nsXPTType::T_WCHAR  :
00082             result++;
00083             break;
00084         default:
00085             // all the others are plain pointer types
00086             result++;
00087             break;
00088         }
00089     }
00090     return result;
00091 }
00092 
00093 static void
00094 invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s)
00095 {
00096     for(PRUint32 i = 0; i < paramCount; i++, d++, s++)
00097     {
00098         if(s->IsPtrData())
00099         {
00100             *((void**)d) = s->ptr;
00101             continue;
00102         }
00103         switch(s->type)
00104         {
00105         case nsXPTType::T_I8     : *((PRInt8*)  d) = s->val.i8;          break;
00106         case nsXPTType::T_I16    : *((PRInt16*) d) = s->val.i16;         break;
00107         case nsXPTType::T_I32    : *((PRInt32*) d) = s->val.i32;         break;
00108         case nsXPTType::T_I64    : *((PRInt64*) d) = s->val.i64; d++;    break;
00109         case nsXPTType::T_U8     : *((PRUint8*) d) = s->val.u8;          break;
00110         case nsXPTType::T_U16    : *((PRUint16*)d) = s->val.u16;         break;
00111         case nsXPTType::T_U32    : *((PRUint32*)d) = s->val.u32;         break;
00112         case nsXPTType::T_U64    : *((PRUint64*)d) = s->val.u64; d++;    break;
00113         case nsXPTType::T_FLOAT  : *((float*)   d) = s->val.f;           break;
00114         case nsXPTType::T_DOUBLE : *((double*)  d) = s->val.d;   d++;    break;
00115         case nsXPTType::T_BOOL   : *((PRBool*)  d) = s->val.b;           break;
00116         case nsXPTType::T_CHAR   : *((char*)    d) = s->val.c;           break;
00117         case nsXPTType::T_WCHAR  : *((wchar_t*) d) = s->val.wc;          break;
00118         default:
00119             // all the others are plain pointer types
00120             *((void**)d) = s->val.p;
00121             break;
00122         }
00123     }
00124 }
00125 
00126 extern "C" {
00127     struct my_params_struct {
00128         nsISupports* that;      
00129         PRUint32 Index;         
00130         PRUint32 Count;         
00131         nsXPTCVariant* params;  
00132         PRUint32 fn_count;     
00133         PRUint32 fn_copy;      
00134     };
00135 }
00136 
00137 XPTC_PUBLIC_API(nsresult)
00138 XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
00139                    PRUint32 paramCount, nsXPTCVariant* params)
00140 {
00141     PRUint32 result;
00142     struct my_params_struct my_params;
00143     my_params.that = that;
00144     my_params.Index = methodIndex;
00145     my_params.Count = paramCount;
00146     my_params.params = params;
00147     my_params.fn_copy = (PRUint32) &invoke_copy_to_stack;
00148     my_params.fn_count = (PRUint32) &invoke_count_words;
00149 
00150 /* This is to call a given method of class that.
00151  * The parameters are in params, the number is in paramCount.
00152  * The routine will issue calls to count the number of words
00153  * required for argument passing and to copy the arguments to
00154  * the stack.
00155  * Since APCS passes the first 3 params in r1-r3, we need to
00156  * load the first three words from the stack and correct the stack
00157  * pointer (sp) in the appropriate way. This means:
00158  *
00159  * 1.) more than 3 arguments: load r1-r3, correct sp and remember No.
00160  *                         of bytes left on the stack in r4
00161  *
00162  * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope),
00163  *              restore sp as if nothing had happened and set the marker r4 to zero.
00164  *
00165  * Afterwards sp will be restored using the value in r4 (which is not a temporary register
00166  * and will be preserved by the function/method called according to APCS [ARM Procedure
00167  * Calling Standard]).
00168  *
00169  * !!! IMPORTANT !!!
00170  * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented
00171  * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])!
00172  *
00173  */
00174  
00175   __asm__ __volatile__(
00176     "ldr      r1, [%1, #12] \n\t"  /* prepare to call invoke_count_words     */
00177     "ldr      ip, [%1, #16] \n\t"  /* r0=paramCount, r1=params        */
00178     "ldr      r0, [%1,  #8] \n\t"
00179     "mov      lr, pc        \n\t"  /* call it...                      */
00180     "mov      pc, ip        \n\t"
00181     "mov      r4, r0, lsl #2       \n\t"  /* This is the amount of bytes needed.    */
00182     "sub      sp, sp, r4    \n\t"  /* use stack space for the args... */
00183     "mov      r0, sp        \n\t"  /* prepare a pointer an the stack  */
00184     "ldr      r1, [%1,  #8] \n\t"  /* =paramCount                            */
00185     "ldr      r2, [%1, #12] \n\t"  /* =params                         */
00186     "ldr      ip, [%1, #20] \n\t"  /* =invoke_copy_to_stack           */
00187     "mov      lr, pc        \n\t"  /* copy args to the stack like the */
00188     "mov      pc, ip        \n\t"  /* compiler would.                 */
00189     "ldr      r0, [%1]      \n\t"  /* =that                           */
00190     "ldr      r1, [r0, #0]  \n\t"  /* get that->vtable offset         */
00191     "ldr      r2, [%1, #4]  \n\t"
00192     "mov      r2, r2, lsl #2       \n\t"  /* a vtable_entry(x)=8 + (4 bytes * x)    */
00193 #if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */
00194     "ldr        ip, [r1, r2]    \n\t"   /* get method adress from vtable        */
00195 #else /* non G++ V3 ABI */
00196     "add      r2, r2, #8    \n\t"  /* with this compilers                    */
00197     "ldr      ip, [r1, r2]  \n\t"  /* get method adress from vtable   */
00198 #endif
00199     "cmp      r4, #12              \n\t"  /* more than 3 arguments???        */
00200     "ldmgtia  sp!, {r1, r2, r3}\n\t"      /* yes: load arguments for r1-r3   */
00201     "subgt    r4, r4, #12   \n\t"  /*      and correct the stack pointer     */
00202     "ldmleia  sp, {r1, r2, r3}\n\t"       /* no:  load r1-r3 from stack             */ 
00203     "addle    sp, sp, r4    \n\t"  /*      and restore stack pointer  */
00204     "movle    r4, #0        \n\t"  /*     a mark for restoring sp            */
00205     "ldr      r0, [%1, #0]  \n\t"  /* get (self)                      */
00206     "mov      lr, pc        \n\t"  /* call mathod                            */
00207     "mov      pc, ip        \n\t"
00208     "add      sp, sp, r4    \n\t"  /* restore stack pointer           */
00209     "mov      %0, r0        \n\t"  /* the result...                   */
00210     : "=r" (result)
00211     : "r" (&my_params)
00212     : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "sp"
00213     );
00214     
00215   return result;
00216 }