Bug 1717205 - Add riscv64gc xptcall support. r=xpcom-reviewers,nika
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Mon, 23 Aug 2021 11:27:04 +0000
changeset 589564 89655737ec45a6e8857536db9cde538563b09ef7
parent 589563 2b096591d6ff69e4d012214bb4f446ec2c744618
child 589565 745a9e5dab53c09b3d7985fbaf6c02f6f82667c6
push id38727
push userapavel@mozilla.com
push dateMon, 23 Aug 2021 15:55:22 +0000
treeherdermozilla-central@108a81c39b3d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersxpcom-reviewers, nika
bugs1717205
milestone93.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1717205 - Add riscv64gc xptcall support. r=xpcom-reviewers,nika Tested on Ubuntu 21.04/riscv64gc with HiFive Unmatched. Differential Revision: https://phabricator.services.mozilla.com/D123056
xpcom/reflect/xptcall/md/unix/moz.build
xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_riscv64.S
xpcom/reflect/xptcall/md/unix/xptcinvoke_riscv64.cpp
xpcom/reflect/xptcall/md/unix/xptcstubs_asm_riscv64.S
xpcom/reflect/xptcall/md/unix/xptcstubs_riscv64.cpp
--- a/xpcom/reflect/xptcall/md/unix/moz.build
+++ b/xpcom/reflect/xptcall/md/unix/moz.build
@@ -258,13 +258,21 @@ if CONFIG["OS_ARCH"] == "Linux":
             "-fomit-frame-pointer",
             "-mbackchain",
         ]
         if CONFIG["CC_TYPE"] == "clang":
             CXXFLAGS += [
                 "-fno-integrated-as",
             ]
 
+if CONFIG["OS_ARCH"] == "Linux" and CONFIG["CPU_ARCH"] == "riscv64":
+    SOURCES += [
+        "xptcinvoke_asm_riscv64.S",
+        "xptcinvoke_riscv64.cpp",
+        "xptcstubs_asm_riscv64.S",
+        "xptcstubs_riscv64.cpp",
+    ]
+
 FINAL_LIBRARY = "xul"
 
 LOCAL_INCLUDES += [
     "../..",
 ]
new file mode 100644
--- /dev/null
+++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_riscv64.S
@@ -0,0 +1,89 @@
+/* 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
+
+    .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    sp, sp, -32
+    .cfi_adjust_cfa_offset 32
+    sd      s0, 16(sp)
+    .cfi_rel_offset s0, 16
+    sd      s1, 8(sp)
+    .cfi_rel_offset s1, 8
+    sd      s2, 0(sp)
+    .cfi_rel_offset s2, 0
+    sd      ra, 24(sp)
+    .cfi_rel_offset ra, 24
+
+    mv      s2, a0
+    mv      s1, a1
+    mv      s0, sp
+    .cfi_def_cfa_register s0
+
+    /* 16-bytes alignment */
+    addiw   a0, a2, 1
+    andi    a0, a0, -2
+    slli    a0, a0, 3
+    sub     sp, sp, a0
+    mv      a4, sp
+
+    addi    sp, sp, -8*(NGPREGS+NFPREGS)
+    mv      a0, sp
+    addi    a1, sp, 8*NGPREGS
+
+    call    invoke_copy_to_stack
+
+    /* 1st argument is this */
+    mv      a0, s2
+
+    ld      a1, 8(sp)
+    ld      a2, 16(sp)
+    ld      a3, 24(sp)
+    ld      a4, 32(sp)
+    ld      a5, 40(sp)
+    ld      a6, 48(sp)
+    ld      a7, 56(sp)
+
+    fld     fa0, 64(sp)
+    fld     fa1, 72(sp)
+    fld     fa2, 80(sp)
+    fld     fa3, 88(sp)
+    fld     fa4, 96(sp)
+    fld     fa5, 104(sp)
+    fld     fa6, 112(sp)
+    fld     fa7, 120(sp)
+
+    addi    sp, sp, 8*(NGPREGS+NFPREGS)
+
+    ld      s2, 0(s2)
+    slliw   s1, s1, 3
+    add     s2, s2, s1
+    ld      t0, 0(s2)
+    jalr    t0
+
+    mv      sp, s0
+    .cfi_def_cfa_register sp
+    ld      s0, 16(sp)
+    .cfi_restore s0
+    ld      s1, 8(sp)
+    .cfi_restore s1
+    ld      s2, 0(sp)
+    .cfi_restore s2
+    ld      ra, 24(sp)
+    .cfi_restore ra
+    addi    sp, sp, 32
+    .cfi_adjust_cfa_offset -32
+    ret
+    .cfi_endproc
+    .size   _NS_InvokeByIndex, . - _NS_InvokeByIndex
+    .section .note.GNU-stack, "", @progbits
new file mode 100644
--- /dev/null
+++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_riscv64.cpp
@@ -0,0 +1,106 @@
+/* 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
+
+#if defined(__riscv_float_abi_soft)
+#  error "Not support soft float ABI"
+#endif
+
+#include "xptcprivate.h"
+
+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:
+          value = s->val.u32;
+          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 {
+        *((double*)d) = s->val.d;
+        d++;
+      }
+    } else if (!s->IsIndirect() && s->type == nsXPTType::T_FLOAT) {
+      if (nr_fpr < FPR_COUNT) {
+        // The value in %fa register is already prepared to
+        // be retrieved as a float. Therefore, we pass the
+        // value verbatim, as a double without conversion.
+        fpregs[nr_fpr++] = s->val.d;
+      } else {
+        *((float*)d) = s->val.f;
+        d++;
+      }
+    } 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);
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/reflect/xptcall/md/unix/xptcstubs_asm_riscv64.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 NGPREGS, 8
+    .set NFPREGS, 8
+
+    .text
+    .globl SharedStub
+    .hidden SharedStub
+    .type  SharedStub,@function
+
+SharedStub:
+    .cfi_startproc
+    mv      t1, sp
+    addi    sp, sp, -8*(NGPREGS+NFPREGS)-16
+    .cfi_adjust_cfa_offset 8*(NGPREGS+NFPREGS)+16
+    sd      a0, 0(sp)
+    sd      a1, 8(sp)
+    sd      a2, 16(sp)
+    sd      a3, 24(sp)
+    sd      a4, 32(sp)
+    sd      a5, 40(sp)
+    sd      a6, 48(sp)
+    sd      a7, 56(sp)
+    fsd     fa0, 64(sp)
+    fsd     fa1, 72(sp)
+    fsd     fa2, 80(sp)
+    fsd     fa3, 88(sp)
+    fsd     fa4, 96(sp)
+    fsd     fa5, 104(sp)
+    fsd     fa6, 112(sp)
+    fsd     fa7, 120(sp)
+    sd      ra, 136(sp)
+    .cfi_rel_offset ra, 136
+
+    /* methodIndex is passed from stub */
+    mv      a1, t0
+    mv      a2, t1
+    mv      a3, sp
+    addi    a4, sp, 8*NGPREGS
+
+    call    PrepareAndDispatch
+
+    ld      ra, 136(sp)
+    .cfi_restore ra
+    addi    sp, sp, 8*(NGPREGS+NFPREGS)+16
+    .cfi_adjust_cfa_offset -8*(NGPREGS+NFPREGS)-16
+    ret
+    .cfi_endproc
+
+    .size SharedStub, . - SharedStub
+    .section .note.GNU-stack, "", @progbits
new file mode 100644
--- /dev/null
+++ b/xpcom/reflect/xptcall/md/unix/xptcstubs_riscv64.cpp
@@ -0,0 +1,160 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#if defined(__riscv_float_abi_soft)
+#  error "Not support soft float ABI"
+#endif
+
+#include "xptcprivate.h"
+
+extern "C" nsresult ATTRIBUTE_USED PrepareAndDispatch(nsXPTCStubBase* self,
+                                                      uint32_t methodIndex,
+                                                      uint64_t* args,
+                                                      uint64_t* gpregs,
+                                                      double* fpregs) {
+  static const uint32_t GPR_COUNT = 8;
+  static const uint32_t FPR_COUNT = 8;
+  nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
+  const nsXPTMethodInfo* info;
+
+  self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
+
+  uint32_t paramCount = info->GetParamCount();
+  const uint8_t indexOfJSContext = info->IndexOfJSContext();
+
+  uint64_t* ap = args;
+  uint32_t nr_gpr = 1;  // skip one GPR register for 'self'
+  uint32_t nr_fpr = 0;
+  uint64_t value;
+
+  for (uint32_t i = 0; i < paramCount; i++) {
+    const nsXPTParamInfo& param = info->GetParam(i);
+    const nsXPTType& type = param.GetType();
+    nsXPTCMiniVariant* dp = &paramBuffer[i];
+
+    if (i == indexOfJSContext) {
+      if (nr_gpr < GPR_COUNT)
+        nr_gpr++;
+      else
+        ap++;
+    }
+
+    if (!param.IsOut() && type == nsXPTType::T_DOUBLE) {
+      if (nr_fpr < FPR_COUNT) {
+        dp->val.d = fpregs[nr_fpr++];
+      } else {
+        dp->val.d = *(double*)ap++;
+      }
+      continue;
+    }
+
+    if (!param.IsOut() && type == nsXPTType::T_FLOAT) {
+      if (nr_fpr < FPR_COUNT) {
+        dp->val.d = fpregs[nr_fpr++];
+      } else {
+        dp->val.f = *(float*)ap++;
+      }
+      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_ERROR("bad type");
+        break;
+    }
+  }
+
+  nsresult result =
+      self->mOuter->CallMethod((uint16_t)methodIndex, info, paramBuffer);
+
+  return result;
+}
+
+// Load t0 with the constant 'n' and branch to SharedStub().
+// clang-format off
+#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      t0, "#n" \n\t"                                                       \
+      "j       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"                                                                      \
+);
+// clang-format on
+
+#define SENTINEL_ENTRY(n)                        \
+  nsresult nsXPTCStubBase::Sentinel##n() {       \
+    NS_ERROR("nsXPTCStubBase::Sentinel called"); \
+    return NS_ERROR_NOT_IMPLEMENTED;             \
+  }
+
+#include "xptcstubsdef.inc"