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 #include "xptcprivate.h"
9
10 #if !defined(__aarch64__)
11 #error "This code is for Linux AArch64 only."
12 #endif
13
14
15 /* "Procedure Call Standard for the ARM 64-bit Architecture" document, sections
16 * "5.4 Parameter Passing" and "6.1.2 Procedure Calling" contain all the
17 * needed information.
18 *
19 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
20 */
21
22 #ifndef __AARCH64EL__
23 #error "Only little endian compatibility was tested"
24 #endif
25
26 // The AAPCS doesn't require argument widening, but Apple's calling convention
27 // does. If we are really fortunate, the compiler will clean up all the
28 // copying for us.
29 template<typename T>
normalize_arg(T value)30 inline uint64_t normalize_arg(T value) {
31 return (uint64_t)value;
32 }
33
34 template<>
normalize_arg(float value)35 inline uint64_t normalize_arg(float value) {
36 uint64_t result = 0;
37 memcpy(&result, &value, sizeof(value));
38 return result;
39 }
40
41 template<>
normalize_arg(double value)42 inline uint64_t normalize_arg(double value) {
43 uint64_t result = 0;
44 memcpy(&result, &value, sizeof(value));
45 return result;
46 }
47
48 /*
49 * Allocation of function arguments to their appropriate place in registers
50 * if possible and then to the stack. Handling of 'that' argument which
51 * goes to register r0 is handled separately and does not belong here.
52 *
53 * Note that we are handling integer arguments and floating-point arguments
54 * identically, depending on which register area is passed to this function.
55 *
56 * 'reg_args' - pointer to the current position in the buffer,
57 * corresponding to the register arguments.
58 * 'reg_args_end' - pointer to the end of the registers argument
59 * buffer.
60 * 'stack_args' - pointer to the current position in the buffer,
61 * corresponding to the arguments on stack.
62 * 'data' - typed data to put on the stack.
63 */
64 template<typename T>
alloc_arg(uint64_t * & reg_args,uint64_t * reg_args_end,void * & stack_args,T * data)65 static inline void alloc_arg(uint64_t* ®_args,
66 uint64_t* reg_args_end,
67 void* &stack_args,
68 T* data)
69 {
70 if (reg_args < reg_args_end) {
71 *reg_args = normalize_arg(*data);
72 reg_args++;
73 } else {
74 // According to the ABI, types that are smaller than 8 bytes are
75 // passed in registers or 8-byte stack slots. This rule is only
76 // partially true on Apple platforms, where types smaller than 8
77 // bytes occupy only the space they require on the stack and
78 // their stack slot must be properly aligned.
79 #ifdef __APPLE__
80 const size_t aligned_size = sizeof(T);
81 #else
82 const size_t aligned_size = 8;
83 #endif
84 // Ensure the pointer is aligned for the type
85 uintptr_t addr = (reinterpret_cast<uintptr_t>(stack_args) + aligned_size - 1) & ~(aligned_size - 1);
86 memcpy(reinterpret_cast<void*>(addr), data, sizeof(T));
87 // Point the stack to the next slot.
88 stack_args = reinterpret_cast<void*>(addr + aligned_size);
89 }
90 }
91
92 extern "C" void
invoke_copy_to_stack(uint64_t * stk,uint64_t * end,uint32_t paramCount,nsXPTCVariant * s)93 invoke_copy_to_stack(uint64_t* stk, uint64_t *end,
94 uint32_t paramCount, nsXPTCVariant* s)
95 {
96 uint64_t* ireg_args = stk;
97 uint64_t* ireg_end = ireg_args + 8;
98 // Pun on integer and floating-point registers being the same size.
99 uint64_t* freg_args = ireg_end;
100 uint64_t* freg_end = freg_args + 8;
101 void* stack_args = freg_end;
102
103 // leave room for 'that' argument in x0
104 ++ireg_args;
105
106 for (uint32_t i = 0; i < paramCount; i++, s++) {
107 if (s->IsIndirect()) {
108 void* ptr = &s->val;
109 alloc_arg(ireg_args, ireg_end, stack_args, &ptr);
110 } else {
111 switch (s->type) {
112 case nsXPTType::T_FLOAT:
113 alloc_arg(freg_args, freg_end, stack_args, &s->val.f);
114 break;
115 case nsXPTType::T_DOUBLE:
116 alloc_arg(freg_args, freg_end, stack_args, &s->val.d);
117 break;
118 case nsXPTType::T_I8:
119 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.i8);
120 break;
121 case nsXPTType::T_I16:
122 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.i16);
123 break;
124 case nsXPTType::T_I32:
125 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.i32);
126 break;
127 case nsXPTType::T_I64:
128 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.i64);
129 break;
130 case nsXPTType::T_U8:
131 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.u8);
132 break;
133 case nsXPTType::T_U16:
134 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.u16);
135 break;
136 case nsXPTType::T_U32:
137 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.u32);
138 break;
139 case nsXPTType::T_U64:
140 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.u64);
141 break;
142 case nsXPTType::T_BOOL:
143 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.b);
144 break;
145 case nsXPTType::T_CHAR:
146 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.c);
147 break;
148 case nsXPTType::T_WCHAR:
149 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.wc);
150 break;
151 default:
152 // all the others are plain pointer types
153 alloc_arg(ireg_args, ireg_end, stack_args, &s->val.p);
154 break;
155 }
156 }
157 }
158 }
159
160 extern "C" nsresult _NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
161 uint32_t paramCount, nsXPTCVariant* params);
162
163 EXPORT_XPCOM_API(nsresult)
NS_InvokeByIndex(nsISupports * that,uint32_t methodIndex,uint32_t paramCount,nsXPTCVariant * params)164 NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
165 uint32_t paramCount, nsXPTCVariant* params)
166 {
167 return _NS_InvokeByIndex(that, methodIndex, paramCount, params);
168 }
169