1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 // Platform specific code to invoke XPCOM methods on native objects
7 
8 // The purpose of NS_InvokeByIndex() is to map a platform
9 // indepenpent call to the platform ABI. To do that,
10 // NS_InvokeByIndex() has to determine the method to call via vtable
11 // access. The parameters for the method are read from the
12 // nsXPTCVariant* and prepared for th native ABI.  For the Linux/PPC
13 // ABI this means that the first 8 integral and floating point
14 // parameters are passed in registers.
15 
16 #include "xptcprivate.h"
17 
18 // 8 integral parameters are passed in registers
19 #define GPR_COUNT     8
20 
21 // With hardfloat support 8 floating point parameters are passed in registers,
22 // floats are promoted to doubles when passed in registers
23 // In Softfloat mode, everything is handled via gprs
24 #ifndef __NO_FPRS__
25 #define FPR_COUNT     8
26 #endif
27 extern "C" uint32_t
invoke_count_words(uint32_t paramCount,nsXPTCVariant * s)28 invoke_count_words(uint32_t paramCount, nsXPTCVariant* s)
29 {
30   return uint32_t(((paramCount * 2) + 3) & ~3);
31 }
32 
33 extern "C" void
invoke_copy_to_stack(uint32_t * d,uint32_t paramCount,nsXPTCVariant * s,uint32_t * gpregs,double * fpregs)34 invoke_copy_to_stack(uint32_t* d,
35                      uint32_t paramCount,
36                      nsXPTCVariant* s,
37                      uint32_t* gpregs,
38                      double* fpregs)
39 {
40     uint32_t gpr = 1; // skip one GP reg for 'that'
41 #ifndef __NO_FPRS__
42     uint32_t fpr = 0;
43 #endif
44     uint32_t tempu32;
45     uint64_t tempu64;
46 
47     for(uint32_t i = 0; i < paramCount; i++, s++) {
48         if(s->IsPtrData()) {
49             if(s->type == nsXPTType::T_JSVAL)
50                 tempu32 = (uint32_t) &s->ptr;
51             else
52                 tempu32 = (uint32_t) s->ptr;
53         }
54         else {
55             switch(s->type) {
56             case nsXPTType::T_FLOAT:                                  break;
57             case nsXPTType::T_DOUBLE:                                 break;
58             case nsXPTType::T_I8:     tempu32 = s->val.i8;            break;
59             case nsXPTType::T_I16:    tempu32 = s->val.i16;           break;
60             case nsXPTType::T_I32:    tempu32 = s->val.i32;           break;
61             case nsXPTType::T_I64:    tempu64 = s->val.i64;           break;
62             case nsXPTType::T_U8:     tempu32 = s->val.u8;            break;
63             case nsXPTType::T_U16:    tempu32 = s->val.u16;           break;
64             case nsXPTType::T_U32:    tempu32 = s->val.u32;           break;
65             case nsXPTType::T_U64:    tempu64 = s->val.u64;           break;
66             case nsXPTType::T_BOOL:   tempu32 = s->val.b;             break;
67             case nsXPTType::T_CHAR:   tempu32 = s->val.c;             break;
68             case nsXPTType::T_WCHAR:  tempu32 = s->val.wc;            break;
69             default:                  tempu32 = (uint32_t) s->val.p;  break;
70             }
71         }
72 
73         if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) {
74 #ifndef __NO_FPRS__
75             if (fpr < FPR_COUNT)
76                 fpregs[fpr++]    = s->val.d;
77 #else
78             if (gpr & 1)
79                 gpr++;
80             if ((gpr + 1) < GPR_COUNT) {
81                 *((double*) &gpregs[gpr]) = s->val.d;
82                 gpr += 2;
83             }
84 #endif
85             else {
86                 if ((uint32_t) d & 4) d++; // doubles are 8-byte aligned on stack
87                 *((double*) d) = s->val.d;
88                 d += 2;
89             }
90         }
91         else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) {
92 #ifndef __NO_FPRS__
93             if (fpr < FPR_COUNT)
94                 fpregs[fpr++]   = s->val.f; // if passed in registers, floats are promoted to doubles
95 #else
96             if (gpr < GPR_COUNT)
97                 *((float*) &gpregs[gpr++]) = s->val.f;
98 #endif
99             else
100                 *((float*) d++) = s->val.f;
101         }
102         else if (!s->IsPtrData() && (s->type == nsXPTType::T_I64
103                                      || s->type == nsXPTType::T_U64)) {
104             if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6
105             if ((gpr + 1) < GPR_COUNT) {
106                 *((uint64_t*) &gpregs[gpr]) = tempu64;
107                 gpr += 2;
108             }
109             else {
110                 if ((uint32_t) d & 4) d++; // longlongs are 8-byte aligned on stack
111                 *((uint64_t*) d)            = tempu64;
112                 d += 2;
113             }
114         }
115         else {
116             if (gpr < GPR_COUNT)
117                 gpregs[gpr++] = tempu32;
118             else
119                 *d++          = tempu32;
120         }
121 
122     }
123 }
124 
125 extern "C"
126 EXPORT_XPCOM_API(nsresult)
127 NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
128                  uint32_t paramCount, nsXPTCVariant* params);
129