diff -r b686e856c800 -r e1c226a4de34 mozilla-aarch64-bmo-963024.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mozilla-aarch64-bmo-963024.patch Sun Apr 13 16:54:09 2014 +0200 @@ -0,0 +1,517 @@ + +# HG changeset patch +# User Marcin Juszkiewicz +# Date 1393440196 18000 +# Node ID d56b5c1a557348d4ac14a4d1ea7a5b5d240e3647 +# Parent 6a46f53ad944b44385398822d7bcf7621a785d91 +Bug 963024 - AArch64 support for XPCOM. r=froydnj + +diff --git a/xpcom/reflect/xptcall/src/md/unix/moz.build b/xpcom/reflect/xptcall/src/md/unix/moz.build +--- a/xpcom/reflect/xptcall/src/md/unix/moz.build ++++ b/xpcom/reflect/xptcall/src/md/unix/moz.build +@@ -144,16 +144,23 @@ if CONFIG['OS_ARCH'] == 'NetBSD': + if CONFIG['OS_TEST'] in ('amiga', 'atari', 'hp300', 'mac68k', 'mvme68k', + 'next68k', 'sun3', 'sun3x', 'x68k'): + SOURCES += [ + 'xptcinvoke_netbsd_m68k.cpp', + 'xptcstubs_netbsd_m68k.cpp' + ] + + if CONFIG['OS_ARCH'] == 'Linux': ++ if CONFIG['OS_TEST'] == 'aarch64': ++ SOURCES += [ ++ 'xptcinvoke_aarch64.cpp', ++ 'xptcinvoke_asm_aarch64.s', ++ 'xptcstubs_aarch64.cpp', ++ 'xptcstubs_asm_aarch64.s', ++ ] + if CONFIG['OS_TEST'] == 'm68k': + SOURCES += [ + 'xptcinvoke_linux_m68k.cpp', + 'xptcstubs_linux_m68k.cpp', + ] + if CONFIG['OS_TEST'].find('mips') != -1: + if CONFIG['OS_TEST'].find('mips64') != -1: + SOURCES += [ +diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_aarch64.cpp b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_aarch64.cpp +new file mode 100644 +--- /dev/null ++++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_aarch64.cpp +@@ -0,0 +1,136 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++/* Platform specific code to invoke XPCOM methods on native objects */ ++ ++#include "xptcprivate.h" ++ ++#if !defined(__aarch64__) ++#error "This code is for Linux AArch64 only." ++#endif ++ ++ ++/* "Procedure Call Standard for the ARM 64-bit Architecture" document, sections ++ * "5.4 Parameter Passing" and "6.1.2 Procedure Calling" contain all the ++ * needed information. ++ * ++ * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf ++ */ ++ ++#ifndef __AARCH64EL__ ++#error "Only little endian compatibility was tested" ++#endif ++ ++/* ++ * Allocation of integer function arguments initially to registers r1-r7 ++ * and then to stack. Handling of 'that' argument which goes to register r0 ++ * is handled separately and does not belong here. ++ * ++ * 'ireg_args' - pointer to the current position in the buffer, ++ * corresponding to the register arguments ++ * 'stack_args' - pointer to the current position in the buffer, ++ * corresponding to the arguments on stack ++ * 'end' - pointer to the end of the registers argument ++ * buffer. ++ */ ++static inline void alloc_word(uint64_t* &ireg_args, ++ uint64_t* &stack_args, ++ uint64_t* end, ++ uint64_t data) ++{ ++ if (ireg_args < end) { ++ *ireg_args = data; ++ ireg_args++; ++ } else { ++ *stack_args = data; ++ stack_args++; ++ } ++} ++ ++static inline void alloc_double(double* &freg_args, ++ uint64_t* &stack_args, ++ double* end, ++ double data) ++{ ++ if (freg_args < end) { ++ *freg_args = data; ++ freg_args++; ++ } else { ++ memcpy(stack_args, &data, sizeof(data)); ++ stack_args++; ++ } ++} ++ ++static inline void alloc_float(double* &freg_args, ++ uint64_t* &stack_args, ++ double* end, ++ float data) ++{ ++ if (freg_args < end) { ++ memcpy(freg_args, &data, sizeof(data)); ++ freg_args++; ++ } else { ++ memcpy(stack_args, &data, sizeof(data)); ++ stack_args++; ++ } ++} ++ ++ ++extern "C" void ++invoke_copy_to_stack(uint64_t* stk, uint64_t *end, ++ uint32_t paramCount, nsXPTCVariant* s) ++{ ++ uint64_t *ireg_args = stk; ++ uint64_t *ireg_end = ireg_args + 8; ++ double *freg_args = (double *)ireg_end; ++ double *freg_end = freg_args + 8; ++ uint64_t *stack_args = (uint64_t *)freg_end; ++ ++ // leave room for 'that' argument in x0 ++ ++ireg_args; ++ ++ for (uint32_t i = 0; i < paramCount; i++, s++) { ++ if (s->IsPtrData()) { ++ alloc_word(ireg_args, stack_args, ireg_end, (uint64_t)s->ptr); ++ continue; ++ } ++ // According to the ABI, integral types that are smaller than 8 bytes ++ // are to be passed in 8-byte registers or 8-byte stack slots. ++ switch (s->type) { ++ case nsXPTType::T_FLOAT: ++ alloc_float(freg_args, stack_args, freg_end, s->val.f); ++ break; ++ case nsXPTType::T_DOUBLE: ++ alloc_double(freg_args, stack_args, freg_end, s->val.d); ++ break; ++ case nsXPTType::T_I8: alloc_word(ireg_args, stk, end, s->val.i8); break; ++ case nsXPTType::T_I16: alloc_word(ireg_args, stk, end, s->val.i16); break; ++ case nsXPTType::T_I32: alloc_word(ireg_args, stk, end, s->val.i32); break; ++ case nsXPTType::T_I64: alloc_word(ireg_args, stk, end, s->val.i64); break; ++ case nsXPTType::T_U8: alloc_word(ireg_args, stk, end, s->val.u8); break; ++ case nsXPTType::T_U16: alloc_word(ireg_args, stk, end, s->val.u16); break; ++ case nsXPTType::T_U32: alloc_word(ireg_args, stk, end, s->val.u32); break; ++ case nsXPTType::T_U64: alloc_word(ireg_args, stk, end, s->val.u64); break; ++ case nsXPTType::T_BOOL: alloc_word(ireg_args, stk, end, s->val.b); break; ++ case nsXPTType::T_CHAR: alloc_word(ireg_args, stk, end, s->val.c); break; ++ case nsXPTType::T_WCHAR: alloc_word(ireg_args, stk, end, s->val.wc); break; ++ default: ++ // all the others are plain pointer types ++ alloc_word(ireg_args, stack_args, ireg_end, ++ reinterpret_cast(s->val.p)); ++ break; ++ } ++ } ++} ++ ++extern "C" nsresult _NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex, ++ uint32_t paramCount, nsXPTCVariant* params); ++ ++EXPORT_XPCOM_API(nsresult) ++NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex, ++ uint32_t paramCount, nsXPTCVariant* params) ++{ ++ return _NS_InvokeByIndex(that, methodIndex, paramCount, params); ++} +diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_aarch64.s b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_aarch64.s +new file mode 100644 +--- /dev/null ++++ b/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_aarch64.s +@@ -0,0 +1,67 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++ .section ".text" ++ .globl _NS_InvokeByIndex ++ .type _NS_InvokeByIndex,@function ++ ++/* ++ * _NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex, ++ * uint32_t paramCount, nsXPTCVariant* params) ++ */ ++ ++_NS_InvokeByIndex: ++ # set up frame ++ stp x29, x30, [sp,#-32]! ++ mov x29, sp ++ stp x19, x20, [sp,#16] ++ ++ # save methodIndex across function calls ++ mov w20, w1 ++ ++ # end of stack area passed to invoke_copy_to_stack ++ mov x1, sp ++ ++ # assume 8 bytes of stack for each argument with 16-byte alignment ++ add w19, w2, #1 ++ and w19, w19, #0xfffffffe ++ sub sp, sp, w19, uxth #3 ++ ++ # temporary place to store args passed in r0-r7,v0-v7 ++ sub sp, sp, #128 ++ ++ # save 'that' on stack ++ str x0, [sp] ++ ++ # start of stack area passed to invoke_copy_to_stack ++ mov x0, sp ++ bl invoke_copy_to_stack ++ ++ # load arguments passed in r0-r7 ++ ldp x6, x7, [sp, #48] ++ ldp x4, x5, [sp, #32] ++ ldp x2, x3, [sp, #16] ++ ldp x0, x1, [sp],#64 ++ ++ # load arguments passed in v0-v7 ++ ldp d6, d7, [sp, #48] ++ ldp d4, d5, [sp, #32] ++ ldp d2, d3, [sp, #16] ++ ldp d0, d1, [sp],#64 ++ ++ # call the method ++ ldr x16, [x0] ++ add x16, x16, w20, uxth #3 ++ ldr x16, [x16] ++ blr x16 ++ ++ add sp, sp, w19, uxth #3 ++ ldp x19, x20, [sp,#16] ++ ldp x29, x30, [sp],#32 ++ ret ++ ++ .size _NS_InvokeByIndex, . - _NS_InvokeByIndex ++ ++ +diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_aarch64.cpp b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_aarch64.cpp +new file mode 100644 +--- /dev/null ++++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_aarch64.cpp +@@ -0,0 +1,219 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "xptcprivate.h" ++#include "xptiprivate.h" ++ ++#ifndef __AARCH64EL__ ++#error "Only little endian compatibility was tested" ++#endif ++ ++/* ++ * This is for AArch64 ABI ++ * ++ * When we're called, the "gp" registers are stored in gprData and ++ * the "fp" registers are stored in fprData. Each array has 8 regs ++ * but first reg in gprData is a placeholder for 'self'. ++ */ ++extern "C" nsresult ++PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint64_t* args, ++ uint64_t *gprData, double *fprData) ++{ ++#define PARAM_BUFFER_COUNT 16 ++#define PARAM_GPR_COUNT 8 ++#define PARAM_FPR_COUNT 8 ++ ++ nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; ++ nsXPTCMiniVariant* dispatchParams = NULL; ++ const nsXPTMethodInfo* info; ++ nsresult result = NS_ERROR_FAILURE; ++ ++ NS_ASSERTION(self,"no self"); ++ ++ self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info); ++ NS_ASSERTION(info,"no method info"); ++ ++ uint32_t paramCount = info->GetParamCount(); ++ ++ // setup variant array pointer ++ if (paramCount > PARAM_BUFFER_COUNT) { ++ dispatchParams = new nsXPTCMiniVariant[paramCount]; ++ } else { ++ dispatchParams = paramBuffer; ++ } ++ NS_ASSERTION(dispatchParams,"no place for params"); ++ ++ uint64_t* ap = args; ++ uint32_t next_gpr = 1; // skip first arg which is 'self' ++ uint32_t next_fpr = 0; ++ for (uint32_t i = 0; i < paramCount; i++) { ++ const nsXPTParamInfo& param = info->GetParam(i); ++ const nsXPTType& type = param.GetType(); ++ nsXPTCMiniVariant* dp = &dispatchParams[i]; ++ ++ if (param.IsOut() || !type.IsArithmetic()) { ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.p = (void*)gprData[next_gpr++]; ++ } else { ++ dp->val.p = (void*)*ap++; ++ } ++ continue; ++ } ++ ++ switch (type) { ++ case nsXPTType::T_I8: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.i8 = (int8_t)gprData[next_gpr++]; ++ } else { ++ dp->val.i8 = (int8_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_I16: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.i16 = (int16_t)gprData[next_gpr++]; ++ } else { ++ dp->val.i16 = (int16_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_I32: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.i32 = (int32_t)gprData[next_gpr++]; ++ } else { ++ dp->val.i32 = (int32_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_I64: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.i64 = (int64_t)gprData[next_gpr++]; ++ } else { ++ dp->val.i64 = (int64_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_U8: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.u8 = (uint8_t)gprData[next_gpr++]; ++ } else { ++ dp->val.u8 = (uint8_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_U16: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.u16 = (uint16_t)gprData[next_gpr++]; ++ } else { ++ dp->val.u16 = (uint16_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_U32: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.u32 = (uint32_t)gprData[next_gpr++]; ++ } else { ++ dp->val.u32 = (uint32_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_U64: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.u64 = (uint64_t)gprData[next_gpr++]; ++ } else { ++ dp->val.u64 = (uint64_t)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_FLOAT: ++ if (next_fpr < PARAM_FPR_COUNT) { ++ memcpy(&dp->val.f, &fprData[next_fpr++], sizeof(dp->val.f)); ++ } else { ++ memcpy(&dp->val.f, ap++, sizeof(dp->val.f)); ++ } ++ break; ++ ++ case nsXPTType::T_DOUBLE: ++ if (next_fpr < PARAM_FPR_COUNT) { ++ memcpy(&dp->val.d, &fprData[next_fpr++], sizeof(dp->val.d)); ++ } else { ++ memcpy(&dp->val.d, ap++, sizeof(dp->val.d)); ++ } ++ break; ++ ++ case nsXPTType::T_BOOL: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.b = (bool)gprData[next_gpr++]; ++ } else { ++ dp->val.b = (bool)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_CHAR: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.c = (char)gprData[next_gpr++]; ++ } else { ++ dp->val.c = (char)*ap++; ++ } ++ break; ++ ++ case nsXPTType::T_WCHAR: ++ if (next_gpr < PARAM_GPR_COUNT) { ++ dp->val.wc = (wchar_t)gprData[next_gpr++]; ++ } else { ++ dp->val.wc = (wchar_t)*ap++; ++ } ++ break; ++ ++ default: ++ NS_ASSERTION(0, "bad type"); ++ break; ++ } ++ } ++ ++ result = self->mOuter->CallMethod((uint16_t)methodIndex, info, dispatchParams); ++ ++ if (dispatchParams != paramBuffer) { ++ delete [] dispatchParams; ++ } ++ ++ return result; ++} ++ ++// Load w17 with the constant 'n' and branch to SharedStub(). ++# define STUB_ENTRY(n) \ ++ __asm__ ( \ ++ ".section \".text\" \n\t" \ ++ ".align 2\n\t" \ ++ ".if "#n" < 10 \n\t" \ ++ ".globl _ZN14nsXPTCStubBase5Stub"#n"Ev \n\t" \ ++ ".hidden _ZN14nsXPTCStubBase5Stub"#n"Ev \n\t" \ ++ ".type _ZN14nsXPTCStubBase5Stub"#n"Ev,@function \n\n" \ ++ "_ZN14nsXPTCStubBase5Stub"#n"Ev: \n\t" \ ++ ".elseif "#n" < 100 \n\t" \ ++ ".globl _ZN14nsXPTCStubBase6Stub"#n"Ev \n\t" \ ++ ".hidden _ZN14nsXPTCStubBase6Stub"#n"Ev \n\t" \ ++ ".type _ZN14nsXPTCStubBase6Stub"#n"Ev,@function \n\n" \ ++ "_ZN14nsXPTCStubBase6Stub"#n"Ev: \n\t" \ ++ ".elseif "#n" < 1000 \n\t" \ ++ ".globl _ZN14nsXPTCStubBase7Stub"#n"Ev \n\t" \ ++ ".hidden _ZN14nsXPTCStubBase7Stub"#n"Ev \n\t" \ ++ ".type _ZN14nsXPTCStubBase7Stub"#n"Ev,@function \n\n" \ ++ "_ZN14nsXPTCStubBase7Stub"#n"Ev: \n\t" \ ++ ".else \n\t" \ ++ ".err \"stub number "#n" >= 1000 not yet supported\"\n" \ ++ ".endif \n\t" \ ++ "mov w17,#"#n" \n\t" \ ++ "b SharedStub \n" \ ++); ++ ++#define SENTINEL_ENTRY(n) \ ++ nsresult nsXPTCStubBase::Sentinel##n() \ ++{ \ ++ NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ ++ return NS_ERROR_NOT_IMPLEMENTED; \ ++} ++ ++#include "xptcstubsdef.inc" +diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_aarch64.s b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_aarch64.s +new file mode 100644 +--- /dev/null ++++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_aarch64.s +@@ -0,0 +1,39 @@ ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++ .set NGPREGS,8 ++ .set NFPREGS,8 ++ ++ .section ".text" ++ .globl SharedStub ++ .hidden SharedStub ++ .type SharedStub,@function ++SharedStub: ++ stp x29, x30, [sp,#-16]! ++ mov x29, sp ++ ++ sub sp, sp, #8*(NGPREGS+NFPREGS) ++ stp x0, x1, [sp, #64+(0*8)] ++ stp x2, x3, [sp, #64+(2*8)] ++ stp x4, x5, [sp, #64+(4*8)] ++ stp x6, x7, [sp, #64+(6*8)] ++ stp d0, d1, [sp, #(0*8)] ++ stp d2, d3, [sp, #(2*8)] ++ stp d4, d5, [sp, #(4*8)] ++ stp d6, d7, [sp, #(6*8)] ++ ++ # methodIndex passed from stub ++ mov w1, w17 ++ ++ add x2, sp, #16+(8*(NGPREGS+NFPREGS)) ++ add x3, sp, #8*NFPREGS ++ add x4, sp, #0 ++ ++ bl PrepareAndDispatch ++ ++ add sp, sp, #8*(NGPREGS+NFPREGS) ++ ldp x29, x30, [sp],#16 ++ ret ++ ++ .size SharedStub, . - SharedStub +