xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_openbsd.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_openbsd.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,183 @@
     1.4 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* Platform specific code to invoke XPCOM methods on native objects */
    1.10 +
    1.11 +#include "xptcprivate.h"
    1.12 +
    1.13 +// Remember that these 'words' are 32bit DWORDS
    1.14 +
    1.15 +static uint32_t
    1.16 +invoke_count_words(uint32_t paramCount, nsXPTCVariant* s)
    1.17 +{
    1.18 +    uint32_t result = 0;
    1.19 +    for(uint32_t i = 0; i < paramCount; i++, s++)
    1.20 +    {
    1.21 +        if(s->IsPtrData())
    1.22 +        {
    1.23 +            result++;
    1.24 +            continue;
    1.25 +        }
    1.26 +        switch(s->type)
    1.27 +        {
    1.28 +        case nsXPTType::T_I8     :
    1.29 +        case nsXPTType::T_I16    :
    1.30 +        case nsXPTType::T_I32    :
    1.31 +            result++;
    1.32 +            break;
    1.33 +        case nsXPTType::T_I64    :
    1.34 +            result+=2;
    1.35 +            break;
    1.36 +        case nsXPTType::T_U8     :
    1.37 +        case nsXPTType::T_U16    :
    1.38 +        case nsXPTType::T_U32    :
    1.39 +            result++;
    1.40 +            break;
    1.41 +        case nsXPTType::T_U64    :
    1.42 +            result+=2;
    1.43 +            break;
    1.44 +        case nsXPTType::T_FLOAT  :
    1.45 +            result++;
    1.46 +            break;
    1.47 +        case nsXPTType::T_DOUBLE :
    1.48 +            result+=2;
    1.49 +            break;
    1.50 +        case nsXPTType::T_BOOL   :
    1.51 +        case nsXPTType::T_CHAR   :
    1.52 +        case nsXPTType::T_WCHAR  :
    1.53 +            result++;
    1.54 +            break;
    1.55 +        default:
    1.56 +            // all the others are plain pointer types
    1.57 +            result++;
    1.58 +            break;
    1.59 +        }
    1.60 +    }
    1.61 +    return result;
    1.62 +}
    1.63 +
    1.64 +static void
    1.65 +invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPTCVariant* s)
    1.66 +{
    1.67 +    for(uint32_t i = 0; i < paramCount; i++, d++, s++)
    1.68 +    {
    1.69 +        if(s->IsPtrData())
    1.70 +        {
    1.71 +            *((void**)d) = s->ptr;
    1.72 +            continue;
    1.73 +        }
    1.74 +        switch(s->type)
    1.75 +        {
    1.76 +        case nsXPTType::T_I8     : *((int8_t*)  d) = s->val.i8;          break;
    1.77 +        case nsXPTType::T_I16    : *((int16_t*) d) = s->val.i16;         break;
    1.78 +        case nsXPTType::T_I32    : *((int32_t*) d) = s->val.i32;         break;
    1.79 +        case nsXPTType::T_I64    : *((int64_t*) d) = s->val.i64; d++;    break;
    1.80 +        case nsXPTType::T_U8     : *((uint8_t*) d) = s->val.u8;          break;
    1.81 +        case nsXPTType::T_U16    : *((uint16_t*)d) = s->val.u16;         break;
    1.82 +        case nsXPTType::T_U32    : *((uint32_t*)d) = s->val.u32;         break;
    1.83 +        case nsXPTType::T_U64    : *((uint64_t*)d) = s->val.u64; d++;    break;
    1.84 +        case nsXPTType::T_FLOAT  : *((float*)   d) = s->val.f;           break;
    1.85 +        case nsXPTType::T_DOUBLE : *((double*)  d) = s->val.d;   d++;    break;
    1.86 +        case nsXPTType::T_BOOL   : *((bool*)  d) = s->val.b;           break;
    1.87 +        case nsXPTType::T_CHAR   : *((char*)    d) = s->val.c;           break;
    1.88 +        case nsXPTType::T_WCHAR  : *((wchar_t*) d) = s->val.wc;          break;
    1.89 +        default:
    1.90 +            // all the others are plain pointer types
    1.91 +            *((void**)d) = s->val.p;
    1.92 +            break;
    1.93 +        }
    1.94 +    }
    1.95 +}
    1.96 +
    1.97 +extern "C" {
    1.98 +    struct my_params_struct {
    1.99 +        nsISupports* that;      
   1.100 +        uint32_t Index;         
   1.101 +        uint32_t Count;         
   1.102 +        nsXPTCVariant* params;  
   1.103 +        uint32_t fn_count;     
   1.104 +        uint32_t fn_copy;      
   1.105 +    };
   1.106 +}
   1.107 +
   1.108 +EXPORT_XPCOM_API(nsresult)
   1.109 +NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
   1.110 +                   uint32_t paramCount, nsXPTCVariant* params)
   1.111 +{
   1.112 +    uint32_t result;
   1.113 +    struct my_params_struct my_params;
   1.114 +    my_params.that = that;
   1.115 +    my_params.Index = methodIndex;
   1.116 +    my_params.Count = paramCount;
   1.117 +    my_params.params = params;
   1.118 +    my_params.fn_copy = (uint32_t) &invoke_copy_to_stack;
   1.119 +    my_params.fn_count = (uint32_t) &invoke_count_words;
   1.120 +
   1.121 +/* This is to call a given method of class that.
   1.122 + * The parameters are in params, the number is in paramCount.
   1.123 + * The routine will issue calls to count the number of words
   1.124 + * required for argument passing and to copy the arguments to
   1.125 + * the stack.
   1.126 + * Since APCS passes the first 3 params in r1-r3, we need to
   1.127 + * load the first three words from the stack and correct the stack
   1.128 + * pointer (sp) in the appropriate way. This means:
   1.129 + *
   1.130 + * 1.) more than 3 arguments: load r1-r3, correct sp and remember No.
   1.131 + *			      of bytes left on the stack in r4
   1.132 + *
   1.133 + * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope),
   1.134 + *		  restore sp as if nothing had happened and set the marker r4 to zero.
   1.135 + *
   1.136 + * Afterwards sp will be restored using the value in r4 (which is not a temporary register
   1.137 + * and will be preserved by the function/method called according to APCS [ARM Procedure
   1.138 + * Calling Standard]).
   1.139 + *
   1.140 + * !!! IMPORTANT !!!
   1.141 + * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented
   1.142 + * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])!
   1.143 + *
   1.144 + */
   1.145 +
   1.146 +#ifdef __GNUC__
   1.147 +  __asm__ __volatile__(
   1.148 +    "ldr	r1, [%1, #12]	\n\t"	/* prepare to call invoke_count_words	*/
   1.149 +    "ldr	ip, [%1, #16]	\n\t"	/* r0=paramCount, r1=params		*/
   1.150 +    "ldr	r0, [%1,  #8]	\n\t"
   1.151 +    "mov	lr, pc		\n\t"	/* call it...				*/
   1.152 +    "mov	pc, ip		\n\t"
   1.153 +    "mov	r4, r0, lsl #2	\n\t"	/* This is the amount of bytes needed.	*/
   1.154 +    "sub	sp, sp, r4	\n\t"	/* use stack space for the args...	*/
   1.155 +    "mov	r0, sp		\n\t"	/* prepare a pointer an the stack	*/
   1.156 +    "ldr	r1, [%1,  #8]	\n\t"	/* =paramCount				*/
   1.157 +    "ldr	r2, [%1, #12]	\n\t"	/* =params				*/
   1.158 +    "ldr	ip, [%1, #20]	\n\t"	/* =invoke_copy_to_stack		*/
   1.159 +    "mov	lr, pc		\n\t"	/* copy args to the stack like the	*/
   1.160 +    "mov	pc, ip		\n\t"	/* compiler would.			*/
   1.161 +    "ldr	r0, [%1]	\n\t"	/* =that				*/
   1.162 +    "ldr	r1, [r0, #0]	\n\t"	/* get that->vtable offset		*/
   1.163 +    "ldr	r2, [%1, #4]	\n\t"
   1.164 +    "mov	r2, r2, lsl #2	\n\t"	/* a vtable_entry(x)=8 + (4 bytes * x)	*/
   1.165 +    "ldr        ip, [r1, r2]    \n\t"	/* get method adress from vtable        */
   1.166 +    "cmp	r4, #12		\n\t"	/* more than 3 arguments???		*/
   1.167 +    "ldmgtia	sp!, {r1, r2, r3}\n\t"	/* yes: load arguments for r1-r3	*/
   1.168 +    "subgt	r4, r4, #12	\n\t"	/*      and correct the stack pointer	*/
   1.169 +    "ldmleia	sp, {r1, r2, r3}\n\t"	/* no:  load r1-r3 from stack		*/ 
   1.170 +    "addle	sp, sp, r4	\n\t"	/*      and restore stack pointer	*/
   1.171 +    "movle	r4, #0		\n\t"	/*	a mark for restoring sp		*/
   1.172 +    "ldr	r0, [%1, #0]	\n\t"	/* get (self)				*/
   1.173 +    "mov	lr, pc		\n\t"	/* call mathod				*/
   1.174 +    "mov	pc, ip		\n\t"
   1.175 +    "add	sp, sp, r4	\n\t"	/* restore stack pointer		*/
   1.176 +    "mov	%0, r0		\n\t"	/* the result...			*/
   1.177 +    : "=r" (result)
   1.178 +    : "r" (&my_params), "m" (my_params)
   1.179 +    : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "sp"
   1.180 +    );
   1.181 +#else
   1.182 +#error "Unsupported compiler. Use g++ >= 2.8 for OpenBSD/arm."
   1.183 +#endif /* G++ >= 2.8 */
   1.184 +
   1.185 +  return result;
   1.186 +}    

mercurial