From 94217bc3650a116df24a592cde9b53fec3b3b722 Mon Sep 17 00:00:00 2001 From: Basilisk-Dev Date: Thu, 8 Jan 2026 09:37:39 -0500 Subject: [PATCH] MoonchildProductions/UXP#2897: backport upstream xptcinvoke and xptcstubs for Loongarch64 --- xpcom/reflect/xptcall/md/unix/moz.build | 7 + .../md/unix/xptcinvoke_asm_loongarch64.S | 91 ++++++++++ .../md/unix/xptcinvoke_loongarch64.cpp | 110 ++++++++++++ .../md/unix/xptcstubs_asm_loongarch64.S | 53 ++++++ .../xptcall/md/unix/xptcstubs_loongarch64.cpp | 170 ++++++++++++++++++ 5 files changed, 431 insertions(+) create mode 100644 xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_loongarch64.S create mode 100644 xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp create mode 100644 xpcom/reflect/xptcall/md/unix/xptcstubs_asm_loongarch64.S create mode 100644 xpcom/reflect/xptcall/md/unix/xptcstubs_loongarch64.cpp diff --git a/xpcom/reflect/xptcall/md/unix/moz.build b/xpcom/reflect/xptcall/md/unix/moz.build index 4b44143ad8..bb05572459 100644 --- a/xpcom/reflect/xptcall/md/unix/moz.build +++ b/xpcom/reflect/xptcall/md/unix/moz.build @@ -114,6 +114,13 @@ if CONFIG['OS_ARCH'] in ('Linux', 'FreeBSD', 'NetBSD', 'OpenBSD'): 'xptcstubs_aarch64.cpp', 'xptcstubs_asm_aarch64.S', ] + if CONFIG['CPU_ARCH'].startswith('loongarch64'): + SOURCES += [ + 'xptcinvoke_asm_loongarch64.S', + 'xptcinvoke_loongarch64.cpp', + 'xptcstubs_asm_loongarch64.S', + 'xptcstubs_loongarch64.cpp', + ] if CONFIG['OS_TEST'] == 'm68k': SOURCES += [ 'xptcinvoke_linux_m68k.cpp', diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_loongarch64.S b/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_loongarch64.S new file mode 100644 index 0000000000..c64ef2b5f5 --- /dev/null +++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_loongarch64.S @@ -0,0 +1,91 @@ +/* This Source Code Form subject to the terms of 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 + + .text + .globl _NS_InvokeByIndex + .type _NS_InvokeByIndex, @function +/* + * _NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex, + * uint32_t paramCount, nsXPTCVariant* params) + */ +_NS_InvokeByIndex: + .cfi_startproc + addi.d $sp, $sp, -32 + .cfi_def_cfa_offset 32 + st.d $s0, $sp, 16 + .cfi_offset 23, -16 + st.d $s1, $sp, 8 + .cfi_offset 24, -24 + st.d $s2, $sp, 0 + .cfi_offset 25, -32 + st.d $ra, $sp, 24 + .cfi_offset 1, -8 + + move $s2, $a0 + move $s1, $a1 + move $s0, $sp + .cfi_def_cfa_register 23 + + /* 16-bytes alignment */ + addi.d $a0, $a2, 1 + li.d $t4, 0xfffffffffffffffe + and $a0, $a0, $t4 + slli.d $a0, $a0, 3 + sub.d $sp, $sp, $a0 + move $a4, $sp + + addi.d $sp, $sp, -8*(NGPREGS+NFPREGS) + move $a0, $sp + addi.d $a1, $sp, 8*NGPREGS + + bl invoke_copy_to_stack + + /* 1st argument is this */ + move $a0, $s2 + + ld.d $a1, $sp, 8 + ld.d $a2, $sp, 16 + ld.d $a3, $sp, 24 + ld.d $a4, $sp, 32 + ld.d $a5, $sp, 40 + ld.d $a6, $sp, 48 + ld.d $a7, $sp, 56 + + fld.d $fa0, $sp, 64 + fld.d $fa1, $sp, 72 + fld.d $fa2, $sp, 80 + fld.d $fa3, $sp, 88 + fld.d $fa4, $sp, 96 + fld.d $fa5, $sp, 104 + fld.d $fa6, $sp, 112 + fld.d $fa7, $sp, 120 + + addi.d $sp, $sp, 8*(NGPREGS+NFPREGS) + + ld.d $s2, $s2, 0 + slli.w $s1, $s1, 3 + add.d $s2, $s2, $s1 + ld.d $t3, $s2, 0 + jirl $ra, $t3, 0 + + move $sp, $s0 + .cfi_def_cfa_register 3 + ld.d $s0, $sp, 16 + .cfi_restore 23 + ld.d $s1, $sp, 8 + .cfi_restore 24 + ld.d $s2, $sp, 0 + .cfi_restore 25 + ld.d $ra, $sp, 24 + .cfi_restore 1 + addi.d $sp, $sp, 32 + .cfi_def_cfa_offset -32 + jirl $zero, $ra, 0 + .cfi_endproc + .size _NS_InvokeByIndex, .-_NS_InvokeByIndex + .section .note.GNU-stack, "", @progbits diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp b/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp new file mode 100644 index 0000000000..1faabdc14d --- /dev/null +++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_loongarch64.cpp @@ -0,0 +1,110 @@ +/* -*- 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(__loongarch64) +#error "This code is for Linux LoongArch64 only." +#endif + +extern "C" void +invoke_copy_to_stack(uint64_t* gpregs, double* fpregs, + uint32_t paramCount, nsXPTCVariant* s, + uint64_t* d) +{ + static const uint32_t GPR_COUNT = 8; + static const uint32_t FPR_COUNT = 8; + + uint32_t nr_gpr = 1; // skip one GPR register for "this" + uint32_t nr_fpr = 0; + uint64_t value = 0; + + for (uint32_t i = 0; i < paramCount; i++, s++) { + if (s->IsIndirect()) { + value = (uint64_t)&s->val; + } else { + switch (s->type) { + case nsXPTType::T_FLOAT: + break; + case nsXPTType::T_DOUBLE: + break; + case nsXPTType::T_I8: + value = s->val.i8; + break; + case nsXPTType::T_I16: + value = s->val.i16; + break; + case nsXPTType::T_I32: + value = s->val.i32; + break; + case nsXPTType::T_I64: + value = s->val.i64; + break; + case nsXPTType::T_U8: + value = s->val.u8; + break; + case nsXPTType::T_U16: + value = s->val.u16; + break; + case nsXPTType::T_U32: + // 32-bit values need to be sign-extended in 64-bit registers, + // so use the signed value here. + value = s->val.i32; + break; + case nsXPTType::T_U64: + value = s->val.u64; + break; + case nsXPTType::T_BOOL: + value = s->val.b; + break; + case nsXPTType::T_CHAR: + value = s->val.c; + break; + case nsXPTType::T_WCHAR: + value = s->val.wc; + break; + default: + value = (uint64_t)s->val.p; + break; + } + } + + if (!s->IsIndirect() && s->type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) { + fpregs[nr_fpr++] = s->val.d; + } else if (nr_gpr < GPR_COUNT) { + memcpy(&gpregs[nr_gpr++], &(s->val.d), sizeof(s->val.d)); + } else { + memcpy(d++, &(s->val.d), sizeof(s->val.d)); + } + } else if (!s->IsIndirect() && s->type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) { + memcpy(&fpregs[nr_fpr++], &(s->val.f), sizeof(s->val.f)); + } else if (nr_gpr < GPR_COUNT) { + memcpy(&gpregs[nr_gpr++], &(s->val.f), sizeof(s->val.f)); + } else { + memcpy(d++, &(s->val.f), sizeof(s->val.f)); + } + } else { + if (nr_gpr < GPR_COUNT) { + gpregs[nr_gpr++] = value; + } else { + *d++ = value; + } + } + } +} + +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/md/unix/xptcstubs_asm_loongarch64.S b/xpcom/reflect/xptcall/md/unix/xptcstubs_asm_loongarch64.S new file mode 100644 index 0000000000..7dd6e3e1cd --- /dev/null +++ b/xpcom/reflect/xptcall/md/unix/xptcstubs_asm_loongarch64.S @@ -0,0 +1,53 @@ +# 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 NGPRGES, 8 + .set NFPREGS, 8 + + .text + .globl SharedStub + .hidden SharedStub + .type SharedStub,@function + +SharedStub: + .cfi_startproc + move $t0, $sp + addi.d $sp, $sp, -8*(NGPRGES+NFPREGS)-16 + .cfi_def_cfa_offset 8*(NGPRGES+NFPREGS)+16 + st.d $a0, $sp, 0 + st.d $a1, $sp, 8 + st.d $a2, $sp, 16 + st.d $a3, $sp, 24 + st.d $a4, $sp, 32 + st.d $a5, $sp, 40 + st.d $a6, $sp, 48 + st.d $a7, $sp, 56 + fst.d $fa0, $sp, 64 + fst.d $fa1, $sp, 72 + fst.d $fa2, $sp, 80 + fst.d $fa3, $sp, 88 + fst.d $fa4, $sp, 96 + fst.d $fa5, $sp, 104 + fst.d $fa6, $sp, 112 + fst.d $fa7, $sp, 120 + st.d $ra, $sp, 136 + .cfi_offset 1, 136 + + /* methodIndex is passed from stub */ + move $a1, $t6 + move $a2, $t0 + move $a3, $sp + addi.d $a4, $sp, 8*NGPRGES + + bl PrepareAndDispatch + + ld.d $ra, $sp, 136 + .cfi_restore 1 + addi.d $sp, $sp, 8*(NGPRGES+NFPREGS)+16 + .cfi_def_cfa_offset -8*(NGPRGES+NFPREGS)-16 + jirl $zero, $ra, 0 + .cfi_endproc + + .size SharedStub, .-SharedStub + .section .note.GNU-stack, "", @progbits diff --git a/xpcom/reflect/xptcall/md/unix/xptcstubs_loongarch64.cpp b/xpcom/reflect/xptcall/md/unix/xptcstubs_loongarch64.cpp new file mode 100644 index 0000000000..c529d3141f --- /dev/null +++ b/xpcom/reflect/xptcall/md/unix/xptcstubs_loongarch64.cpp @@ -0,0 +1,170 @@ +/* -*- 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" + +#if !defined(__loongarch64) +#error "This code is for Linux LoongArch64 only." +#endif + +extern "C" nsresult ATTRIBUTE_USED +PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, + uint64_t* args, uint64_t* gpregs, double* fpregs) +{ +#define PARAM_BUFFER_COUNT 16 + + static const uint32_t GPR_COUNT = 8; + static const uint32_t FPR_COUNT = 8; + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = paramBuffer; + const nsXPTMethodInfo* info; + + NS_ASSERTION(self, "no self"); + + self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info); + NS_ASSERTION(info, "no method info"); + + uint32_t paramCount = info->GetParamCount(); + + if (paramCount > PARAM_BUFFER_COUNT) { + dispatchParams = new nsXPTCMiniVariant[paramCount]; + } + NS_ASSERTION(dispatchParams, "no place for params"); + + uint64_t* ap = args; + uint32_t nr_gpr = 1; // skip the arg which is 'self' + uint32_t nr_fpr = 0; + uint64_t value = 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 == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) { + dp->val.d = fpregs[nr_fpr++]; + } else if (nr_gpr < GPR_COUNT) { + memcpy(&dp->val.d, &gpregs[nr_gpr++], sizeof(dp->val.d)); + } else { + memcpy(&dp->val.d, ap++, sizeof(dp->val.d)); + } + continue; + } + + if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) { + memcpy(&dp->val.f, &fpregs[nr_fpr++], sizeof(dp->val.f)); + } else if (nr_gpr < GPR_COUNT) { + memcpy(&dp->val.f, &gpregs[nr_gpr++], sizeof(dp->val.f)); + } else { + memcpy(&dp->val.f, ap++, sizeof(dp->val.f)); + } + continue; + } + + if (nr_gpr < GPR_COUNT) { + value = gpregs[nr_gpr++]; + } else { + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*)value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: + dp->val.i8 = (int8_t)value; + break; + case nsXPTType::T_I16: + dp->val.i16 = (int16_t)value; + break; + case nsXPTType::T_I32: + dp->val.i32 = (int32_t)value; + break; + case nsXPTType::T_I64: + dp->val.i64 = (int64_t)value; + break; + case nsXPTType::T_U8: + dp->val.u8 = (uint8_t)value; + break; + case nsXPTType::T_U16: + dp->val.u16 = (uint16_t)value; + break; + case nsXPTType::T_U32: + dp->val.u32 = (uint32_t)value; + break; + case nsXPTType::T_U64: + dp->val.u64 = (uint64_t)value; + break; + case nsXPTType::T_BOOL: + dp->val.b = (bool)(uint8_t)value; + break; + case nsXPTType::T_CHAR: + dp->val.c = (char)value; + break; + case nsXPTType::T_WCHAR: + dp->val.wc = (wchar_t)value; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + nsresult result = self->mOuter->CallMethod((uint16_t)methodIndex, info, + dispatchParams); + + if (dispatchParams != paramBuffer) { + delete [] dispatchParams; + } + + return result; +} + +// Load $t6 with the constant 'n' and branch to SharedStub(). +#define STUB_ENTRY(n) \ + __asm__( \ + ".text\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" \ + "li.d $t6, "#n" \n\t" \ + "b SharedStub \n" \ + ".if "#n" < 10 \n\t" \ + ".size _ZN14nsXPTCStubBase5Stub"#n"Ev,.-_ZN14nsXPTCStubBase5Stub"#n"Ev\n\t" \ + ".elseif "#n" < 100 \n\t" \ + ".size _ZN14nsXPTCStubBase6Stub"#n"Ev,.-_ZN14nsXPTCStubBase6Stub"#n"Ev\n\t" \ + ".else \n\t" \ + ".size _ZN14nsXPTCStubBase7Stub"#n"Ev,.-_ZN14nsXPTCStubBase7Stub"#n"Ev\n\t" \ + ".endif" \ +); + +#define SENTINEL_ENTRY(n) \ + nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0, "nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc"