Skip to content

我们的工作习惯

Levi Zim edited this page Dec 18, 2023 · 7 revisions

不是让软件能出包就算修复,对于 Patch 的内容我们有着一些不成文的约定。你可以在这篇文章中了解我们以往对某个错误的通用修复方式,也可以了解我们的一些要求。

XX is not available for the 'riscv64' architecture

这是因为 PKGBUILD 的 arch 数组设置 riscv64 的值。 请不要把 arch 改为 any,any 表示不同架构出的包二进制上没有区别。

你可以用 setconf 重新设置值:

setconf PKGBUILD arch '(riscv64 x86_64)'

还有请注意不要提交对 arch 的修改。

修代码优先还是改编译 flag 优先?

优先修代码。

参考: https://build.opensuse.org/package/view_file/devel:ARM:Factory:Contrib:ILP32/presage/presage-0.9.1-gcc11.patch?expand=0

tarball URL 变了该怎么办

给 Arch 交 BUG

版本号

版本号不要超过主线,尽量以催更为主。 如果实在不行就加一行注释,提一下上游的进度,让以后维护的人有个参考。

循环依赖

有些包可以一起打,但在状态页上显示互相缺了对方,这种需要 bootstrap。

详细参考 ghc bootstrap Patch: https://github.com/felixonmars/archriscv-packages/pull/17/commits/36279fff5314fbcd212549ede73db5257ef10b1d

patch hunk offset

Q: 平时更新 patch 的时候,如果有代码的 patch hunk 飘了,能打上但是有 offset,需要 把 patch 更新成最新的行号吗?

A: 不需要

测试

如果有的包不在乎测试是否通过,比如 test || echo,那可以直接把测试注释掉。

访问一些会在编译期被删除的文件

有一个比较脏的做法:往 PKGBUILD 里加一句 bash -i,然后就用这个 subshell 来交互 build env。

关于 upstream

如果上游的 maintainer 是肥猫的话,可以直接在群里 @ 肥猫。

Python 2to3

Python 的包不管 major version 都要跑一次 2to3。

qemu-user-blacklist.txt

当且仅当包出错的原因来源于 QEMU User 的 BUG 本身,且其他 riscv 机器无法复现此 BUG 的时候,才可以往这个清单里加新的包。

为什么我们不尝试对 qemu user 进行修复呢?

现在我们遇到好几个 qemu 挂死的版本,我们维护了好几个版本

  1. 首先是这个 always-malloc,我们手打了个 glib,稍微缓解了一些 https://github.com/ZenithalHourlyRate/glib
  2. 然后 qemu 在 futex pi 这个 syscall 上翻译不行,这在某些 glibc 版本下会导致 pthread 挂(影响所有 qemu-user 版本,不只 riscv),然后粗糙搓了一个https://github.com/ZenithalHourlyRate/qemu
  3. 我们还发现一些情况下进程会 Z 掉(打 rust 的时候),我们猜测和这个 issue 有关 https://gitlab.com/qemu-project/qemu/-/issues/140 ,但看起来非常 non-trivial 不好修,称其为 vfork 吧
  4. 在 always-malloc 修了以后,我们依然会遇到和 1 一样的 futex hang 的问题(打 go 的时候),我们还没调查咋回事

为什么要选择手动维护 noqemu blacklist 这种看似低效的方式呢?

根据测试,QEMU-User 编译速度大于 RISC-V 板子大于 QEMU-System, 手工维护 noqemu blacklist 其实效率反而更高一些。

修改 qemu-user-blacklist.txt

该文件应该保持字典序, 可以通过以下命令向该文件中添加一个新的包:

echo "包名" | LC_ALL=C sort -o qemu-user-blacklist.txt - qemu-user-blacklist.txt

注意 LC_ALL=C 是必须的. 不指定 LC_ALL=C 会导致 sort 按照当前系统的本地化设置进行排序, 可能会忽略除字母和数字之外的其他字符, 导致最后顺序不一样. 参考 man sort 和此链接.

Unknown public key....

这是因为本地的 gpg 数据库没有这个开发者的公钥。你可以用命令 gpg --recv-key keyid 下载并导入这个 key。

Arch Linux 最近通过了把 key 放到 SVN 的 RFC,在 PKGBUILD 同级目录下会有 key 文件夹放置这些 gpg key。 如果找不到 key 就到上游开 bug report 让他们把 key 放到 git 里。 如果你找到了 key,而且上游没动静,可以暂时先把 key 和 riscv64.patch 放一起提交到肥猫仓库。

如果遇到了 gpg: keyserver receive failed: No data 这样的错误,大概率是 keyserver 被橄榄了。

sks pool 因为是单增的,无法满足 GDPR 对被遗忘权的规定, 被欧盟法律橄榄了。

你可以先尝试在下面几个 sks 镜像看看能不能找到:

https://pgp.surfnet.nl/
pgp.uni-mainz.de 11370
pgp.circl.lu 11370
keys.andreas-puls.de 11370

使用 gpg --keyserver https://example.com --recv-key keyid 来指定下载服务器。

如果还是找不到,可以找找他们项目主页,团队介绍,个人博客等等等页面。如果是 GitHub 的项目,你可以找到那个开发者的主页,然后在后面加上 .gpg 来查看他的 key。

https://github.com/user.gpg
                       ^^^^

然后用 gpg import 导入: curl https://github.com/user.gpg | gpg --import。下载完之后可以往其他公共服务器上都丢一份。


如果实在是找不到 key,但是又急着测试,可以用参数 --skippgpcheck 暂时跳过检查。

extra-riscv64-build -- -d "..." -- --skippgpcheck
                                 # ^^^^^^^^^^^^^^^^^ 多用一个 -- 把 skippgpcheck 传给更下层的 makepkg

或者可以参考这个: https://github.com/archlinuxcn/lilac/blob/master/recv_gpg_keys

Rust

error: failed to run rustc to learn about target-specific information

解决方案:删除 PKGBUILD 里的 --target "$CARCH-unknown-linux-gnu" 参数

这个问题源自于 Rust 和 LLVM 的 Triple 定义不一致。Rust 学 GCC 搞 rv64<ext> 这样的风格,于是 --target 期待输入 riscv64gc-unknown-linux-gnu,但 CARCH 并不是这样的风格,于是就会传入 riscv64-unknown-linux-gnu 这样的字符串。

References:

error: failed to run custom build command for ring v0.16.20

解决方案:使用肥猫 patch 后的 ring。在 PKGBUILD 的 prepare 函数(如果没有这个函数就自己加上)内加入下面两行:

echo -e "\n[patch.crates-io]\nring = { git = 'https://github.com/felixonmars/ring', branch = '0.16.20' }" >> Cargo.toml
cargo update -p ring

无法编译 jemallocator 这个依赖

解决方案:给上游发 PR,把 jemallocator 这个 crate 换成 tikv-jemallocator。

参考 PR:

在 QEMU-user 里编译 Rust 程序卡住了

打开 htop,摁 F4 搜索编译程序的名字,可以用方向键移动。在 S 那一列里查看应用状态,如果是 Z,即 Zombie 僵尸状态,说明编译程序卡死了,需要杀掉重开。选上这个程序之后按 k 键,左侧会弹出 Send Signal 窗口,选择 SIGABRT 信号并回车,程序就会被干掉了,然后你再重试。

Cargo component is not applicable...

error:
  the 'cargo' binary, normally provided by the 'cargo' component,
  is not applicable to the 'stable-2020-12-31-x86_64-unknown-linux-gnu' toolchain

这个错误源自于 rustup 因为更新中断或其他错误,只部分更新了工具链。这个问题不是很好修,我的建议是重新安装 cargo 工具链,能更快解决问题。

xxx have differnt source paths...

之前曾经想过往上游 PR 架构特定的依赖链接。比如像下面这样,在普通的环境使用 4.4.0 版本,在 riscv64 里用我 fork 并修好的版本。

[depedencies.ffmepg-sys-next]
version="4.4.0-next.2"
default-features=false

[target.'cfg(target_arch="riscv64")'.dependencies.ffmpeg-sys-next]
git="https://github.com/Avimitin/rust-ffmpeg-sys"
branch="risc-v"

但是这样是无法编译的:

Caused by:
  Dependency 'ffmpeg-sys-next' has different source paths depending on the build target.
  Each dependency must have a single canonical source path irrespective of build target.

Cargo 不支持对同一个依赖使用不同的源。 你可以这么写:

[depedencies]
A
B

[target.'cfg(target_arch="riscv64")'.dependencies]
C
D

但是不能这么写:

[depedencies]
A = { git = "https://github.com/UserA/crate" }

[target.'cfg(target_arch="riscv64")'.dependencies]
A = { git = "https://github.com/UserB/crate" }

在依赖里用了 git 之后指定的 feature 无效了

当这样设置依赖的时候,指定的 feature 不会被编译

[dependencies.dashmap]
git = "https://github.com/Avimitin/dashmap"
branch = "risc-v"
features = ["serde"]

暂时不知道什么原因。会导致编译的时候有的 trait 没有实现在 struct 上导致传参失败之类的错误等等。

如果遇到某个模块没法编译 features 进去的话,优先把他这个包修了然后发 PR 到上游。

Golang

替换依赖

编辑 go.mod,用 replace 语法进行替换(可以放在文件最后面)。

例子:把 modernc.org/libc 的 v1.4.1 版本升到 v1.14.11 版本

replace modernc.org/libc v1.4.1 => modernc.org/libc v1.14.11

然后把这个修改生成出 patch,在 PKGBUILD 的 prepare 函数里添加:

patch -Ni ../fix-libc.patch
go get -d modernc.org/libc

最后把 riscv64.patch 和修改的 patch 放在一起,提交 PR。

Patch go dep

go mod edit -replace github.com/prometheus/client_golang=github.com/prometheus/client_golang@efe7aa7
go mod download github.com/prometheus/client_golang

# 这个是根据不加 go get 的报错提示来添加的
# 没报错可以不用加,注意要去掉版本号(@ 后面的部分)
go get github.com/prometheus/client_golang/prometheus

go generate  # if necessary
cd cmd/traefik
go build

具体参考: https://github.com/felixonmars/archriscv-packages/pull/346/files

给 go 包的依赖(的依赖)打patch的正确方式

Go 比较特殊,Go 是在 build 的时候 install。 假设有一系列的依赖链:a->b->c->d->e。 如果需要修 d,则 bcd 都需要 fork,修好 d 之后 bc 改依赖。

Go 还可以在 go.mod 里用 replace 语法来替换依赖:

replace github.com/creack/goselect => github.com/creack/goselect v0.1.2

具体参考: https://github.com/felixonmars/archriscv-packages/pull/387/commits/ad0e66c31b21efd93fff93be8cce5b9e13b59953

编译 golang 包的时候经常卡死

QEMU 的锅,直接杀掉重新开始。

bad pointer

runtime: bad pointer in frame ... at 0x...
fatal error: invalid pointer found on stack

可以跟踪一下这个 issue: https://github.com/golang/go/issues/51101

以后 go build 的时候加上这个 flag -gcflags=all="-N -l",并且往上面那个 issue 报一下。

C/C++

config.guess: unable to guess system type

解决方案:

  1. 首先向上游汇报他们的 config.guessconfig.sub 文件过老。请一定要向上游报告! config.sub 上游有职责及时更新。
  2. 然后在 PKGBUILD 里尝试使用 autoreconf -fi 命令来更新 config.guess
  3. 如果上游的 config.guess 文件已经老到无法更新,将 /usr/share/autoconf/build-aux/ 目录下的 config.guessconfig.sub 文件拷贝到本地。
  4. 提交 PR,并附带上你的上游汇报链接。
  5. 持续跟踪你的上游报告,等上游更新完并发版之后删除仓库里的 patch。

Executable "wasm-ld" doesn't exist! (STUCK)

要安装 lld,wasm-ld 只在 lld 里面有。Firefox 的话,引入 lld 会带来另外的问题。lld 是需要默认关闭的, 问题来源于 -mno-relax-mrelax

可以查看这个 PR 了解详情 https://github.com/felixonmars/archriscv-packages/pull/139

pthread related issue

标准答案: PR #1035

gcc atomic

gcc 的 1B 2B atomic 实现在 riscv64 有问题。gcc 的 1B 2B atomic 实现需要跑到 libatomic, 于是没法在编译期判断是否无锁

ref: https://code.videolan.org/videolan/vlc/-/issues/20683

The GCC docs make it clear that -pthread is the correct way to use the pthread library on POSIX systems. Not only does it add extra necessary linker options for some targets, but it also adds some extra necessary preprocessor options for many targets. There is also the issue that the library is called -lpthread on some systems, and -lpthreads on others. The -pthread option handles this correctly.

It is a known problem that the RISC-V gcc atomic support needs more work. RISC-V only supports 4 and 8 byte atomic operations in hardware. 1 and 2 byte operations are implemented using instruction sequences with locks, and this is currently done via a call into libatomic. However, mixing lock free and non-locking atomic sequences can potentially cause run-time failures. We need to instead emit instruction sequences using 4 and/or 8 byte atomic instructions without locks. This is on the list of things that need to be fixed, but there are a lot of things that need to be fixed and we haven't gotten around to fixing this one yet. This definitively needs to be fixed before gcc 9, and hopefully much sooner than that.

While the RISC-V gcc port does need to be fixed, it is still true that you should be using -pthread instead of -lpthread.

除此之外还有一个很诡异的事情:就是在 gcc 里,std::atomic<bool>::is_always_lock_free 是 false,std::atomic<int>::is_always_lock_free 是 true。但是如果你在运行的时候 整一个 bool b; std::atomic_is_lock_free(&b),你会发现它是 true,而且是,不管怎么试, 在哪试,它都是 true。

在 gcc 里面大概 ATOMIC_BOOL_LOCK_FREE 是 1(1 for the built-in atomic types that are sometimes lock-free)

ref: https://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg664254.html

tldr: 只能等 gcc 的人实现 sub-word lock-free atomic 了

All atomic types except for std::atomic_flag may be implemented using mutexes or other locking operations, rather than using the lock-free atomic CPU instructions. Atomic types are also allowed to be sometimes lock-free, e.g. if only aligned memory accesses are naturally atomic on a given architecture, misaligned objects of the same type have to use locks.

Thanks for the detailed writeup!

Your analysis is basically correct, but I would add that ICC's behavior here is unsound (it only appears to "implement[] this behavior correctly" in simple cases) whereas the GCC/Clang behavior is sound but surprising. For GCC, ICC, and Clang, identity <fp> and identity<float> are the same type. Therefore it's not possible for identity <fp>::type and identity<float>::type to have different alignments, because they're the same type. So, for an example such as this:

typedef float fp  __attribute__((aligned(16)));
std::cout << alignof(typename identity<fp>::type) << std::endl;
std::cout << alignof(typename identity<float>::type) << std::endl;

under GCC and Clang, both lines print out 4, whereas under ICC, they either both print out 4 or both print out 16 depending on which one happens to appear first in the program (and in general you can encounter ODR violations when using ICC despite there being nothing wrong at the source level).

Fundamentally, the 'aligned' attribute is a GCC extension, so the GCC folks get to define how it works. And they chose that instead of it resulting in a different type that's almost like the original type (for example, treating it as a type qualifier), it results in the same type, but that in some contexts that same type behaves differently. That's a semantic disaster, but it's what we live with. And in particular, the only way for template instantiation to be sound in the presence of this semantic disaster is for it to ignore all such attributes on template type arguments.

-fno-common

Q: -fno-common 取代了 -fcommon, 这种情况优先 -fno-common 还是 patch source?

A: 优先 patch source。 一般来说能不动flags尽量不动。 少数例外是,比如,这个项目死了十年了,连个repo都找不到。

不过如果是 -fcommon 这种,比较推荐的是先提给上游,咱们patch着打。 这样下次上游发版本arch那边更新的时候,就会莫名其妙好了,他们不用做什么,我们也只用删掉patch。

-Wno-format

如果遇到 cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security], 这个错误是因为代码被编译的时候,CFLAG 选项多了一个 -Wno-format,这个选项会关闭 -Wformat,但 -Werror=format-security 仍然保留着。

解决方案首先是让上游修,然后引用 patch,参考上面那一章节。

如果是一万年不更新的代码仓库,那可以酌情使用 ${CFLAG#-Werror=format-security} 或者 sed -i 's/ -Werror=format-security // Makefile 把这个选项删除。

但是尽量现在群里讨论,问问前辈的意见。

-Werror=format-security

-Wformat-security
   If -Wformat is specified, also warn about uses of format functions that represent possible security problems.  At present, this warns about calls to "printf" and "scanf" functions where the
   format string is not a string literal and there are no format arguments, as in "printf (foo);".  This may be a security hole if the format string came from untrusted input and contains %n.
   (This is currently a subset of what -Wformat-nonliteral warns about, but in future warnings may be added to -Wformat-security that are not included in -Wformat-nonliteral.)

首先,优先给上游发补丁。从 manpage 也可以看的出来,只需要把 printf 改成 printf("%s") 的形式即可。

除非上游十多年没动静,才可以选择把这个选项删掉。 可以用: CFLAGS=${CFLAGS/-Werror=format-security/}

如果上游很难沟通,或者上游代码不太好修,优先自己修,然后和群里的前辈商量一下解决方案。

Reference: https://github.com/felixonmars/archriscv-packages/pull/559

SSE Related issue

放到 riscv 板子上跑,然后标 noqemu

现在可以用 simde2 来模拟 SSE2 实现,以提供 SSE2 支持,具体可以参考这个 PR: #3011

Intel related

Intel 的一些包,没留 Generic 实现,只有 x86 simd 的,比如 hyperscan, 这种包就直接跳过不管了。

Qmake

使用 qmake 构建的包构建时提示 Could not find qmake spec 'default'.

这种情况目前需要去板子上打包。

msse

Error: c++: error: unrecognized command-line option '-msse'

这是因为 -msse 这个编译选项暂时还不支持 x86_64 以外的 Arch, 你需要查看一下这个项目的 CMakeList 选项,暂时把他关闭。

比如 cmake -DSSE=OFF

gcc nostdlib

-nostdlib 会覆盖 -pthread

glibc optimization

error: glibc cannot be compiled without optimization

solution: 加上 -O1

unguarded-availability-new

Error:

cc1plus: error: ‘-Werror=unguarded-availability-new’: no option ‘-Wunguarded-availability-new’

这个选项只有 clang 才有,如果没有强制使用 GNU 的构建工具, 可以设置环境变量 CC=clang CXX=clang++ 强制使用 clang 来编译。

如果这个项目用的 cmake,可以加两个参数:

"-DCMAKE_C_COMPILER=clang"
"-DCMAKE_CXX_COMPILER=clang++"

同时记得给上游报 BUG 让他们默认使用 clang 来编译。

Electron

v8 版本低于 9.0 的就不用修了,从 9.0 开始有实验性的 risc-v 支持。

node-sass

node-sass v6 就是不支持 node v17 的,node-sass 对 njs v17 的支持始于版本 7.0.0, 6.x 支持的 njs version:12, 14, 15, 16,所以要么就把 dependency 从 nodejs 改成 nodejs-lts-gallium, 要么就催上游更新 package.json 里 node-sass 的版本,which is nonsense,因为大版本号的更新往往带来不兼容。

invalid or corrupted package (pgp signature)

如果在构建 any 包的时候遇到这个问题,可能是因为缓存冲突问题。 x86_64 和 riscv64 下的 any 包的名字是一样的,但是这两个的签名不同。 如果有人构建包的时候没建缓存目录,完事儿了也没删掉, 当构建的时候用到了别人的缓存就会出现这个问题。

解决方案:

  • 自建 cache 目录
  • 删了缓存重新跑构建

磁盘占用满了

lto: fatal error: write: No space left on device

很有可能不是真的吃满了,是因为 devtools 使用了 systemd-nspawn,而后者默认用参数 size=10% 挂载在 /tmp 目录上。

可以尝试调整 SYSTEMD_NSPAWN_TMPFS_TMP 这个变量的值来拒绝挂载 tmpfs

SYSTEMD_NSPAWN_TMPFS_TMP=0 extra-x86_64-build

记得需要加上 sudo 用 root 跑,不然 devtools 自己 sudo 了之后,这个环境变量就没了。

大量依赖缺失

不一定是所有依赖都不匹配,pacman 是 depends=(a, b, c, d, e), 然后如果 e 缺了它会说 a b c d e not found

nodejs 的某些包出现怪异的错误

目前 nodejs 在部分机器上可能出现怪异行为,包括但不限于:segfault, SIGILL, SIGTRAP, busy hang, 出现怪异报错然后退出等, 比如:

Tracking issue: https://github.com/revyos/revyos/issues/27

解决方案暂时是换其他机器。

另外目前主要有如下 V8 bug 影响打包,触发条件基本都是 lodash:

https://bugs.chromium.org/p/v8/issues/detail?id=13930

如果遇到了上面的问题之外的问题,可以

  1. 尝试禁用 JIT 或 TurboFan
    • 设置环境变量 NODE_OPTIONS='--jitless' 或者给 node 传 --jitless. 但是这会一并禁用 WebAssembly. 好处是用环境变量传递不用 patch 代码
    • 给 Node 加上 --max-opt=0 参数. 这实际上是一个 V8 的参数. 这个参数不能通过环境变量传递, 需要 patch 代码, 但是不会禁用 WebAssembly.
  2. 对多个版本的 Node.js 进行试验

来确认是否是特定版本的 Node.js/V8/V8 JIT 的 Bug.

如果在新版的 Node.js 上无法复现,那么大概率是新版的 V8 修复了这个问题,我们可以尝试将修复的 commit backport 到旧版的 Node.js 中。

Node.js 对应的 V8 版本可以在 deps/v8/include/v8-version.h 中找到, 例如:

Node.js 19.0.0: https://github.com/nodejs/node/blob/v19.0.0/deps/v8/include/v8-version.h

#define V8_MAJOR_VERSION 10
#define V8_MINOR_VERSION 7
#define V8_BUILD_NUMBER 193
#define V8_PATCH_LEVEL 13

对应的 V8 的版本是 10.7.193.13.

首先,为了确定修复的 commit 的位置,我们可以在 V8 的 git repo 中使用 git loggrep 来搜索相关的 commit.

node.js 18 在运行 npx vite --version 时的问题为例:

该问题在 Node.js 19 上无法复现,Node.js 18 上可以复现,对应的 V8 版本是 10.2.154.26..10.7.193.13

查看这段范围内的 riscv 相关的 commit,优先尝试 backport Fix 类型的 commit。

git log --oneline 10.2.154.26..10.7.193.13 | grep riscv
b1a147705e4 [riscv] Port [wasm][liftoff] Fix and cleanup tracing of return value
2987a4ea51d [riscv] Port [log][compiler] Enable first-execution logging
184efc149a2 [riscv] Fix cctest/test-assembler-riscv*/RISCV_UTEST_FLOAT_WIDENING_vfwadd_vf.
d17bc74fc0b [riscv] Fix cctest/test-assembler-riscv64/RISCV_UTEST_swlwu.
931828a6a15 [riscv] Port [wasm][simd] Fix SpillAdjacentFpRegisters
dad963c84f9 [riscv] Separate single and double precision zero to different registers to avoid misuse.
7370cb97752 [riscv]Port [wasm] Keep call_indirect index on the stack
f8aebf80023 Reland "[riscv] Port [heap] Add shared barrier to RecordWrite builtin"
8b6e23ccd7a Revert "[riscv] Port [heap] Add shared barrier to RecordWrite builtin"
59d7cf5259d [riscv] Port [heap] Add shared barrier to RecordWrite builtin
c093aff6c4a [riscv64][wasm-relaxed-simd] Implement relaxed i16x8.q15mulr_s
546c7b5f590 Reland "[WATCHLISTS] Add riscv watch"
4516d7ca445 Revert "[WATCHLISTS] Add riscv watch"
8140809ecea [riscv] Fix wasm/generic-wrapper test failed
d94cb639978 [riscv]Fix temporary register reuse
613c24028b9 [riscv][masm] Move tiering logic to macro-assembler
41cc719643d [riscv32] fix wasm-spec-test/i64.js
4ae65adedd7 [riscv][masm][cleanup] Refactor call related assembler options
e71be343616 [riscv][ext-code-space] Add InterpreterEntryTrampolineForProfiling builtin
ccc3138e046 [riscv] Fix wasm/externref-globals-liftoff failed
a271ab14af5 [riscv] Fix asm atomic op test case failed
d851e71ae1a [riscv] Fix native build
d631c1efdaa [riscv64]  disable fp multiply and accumulate instructions
942a67ca018 Reland "[riscv32] Add RISCV32 backend"
0c785c07609 [riscv] Reland: [wasm] WasmCompileLazyFrame scanning
c0d5d4d60a3 Revert "[riscv32] Add RISCV32 backend"
776b9eb9d9f [WATCHLISTS] Add riscv watch
637b591934b Reland "[riscv][Cleanup] Use CmpInstanceTypeRange in MacroAssembler"
2e0f9c51e48 Revert "[riscv][Cleanup] Use CmpInstanceTypeRange in MacroAssembler"
859ff489615 [riscv][Cleanup] Use CmpInstanceTypeRange in MacroAssembler
491de34bcc8 [riscv32] Add RISCV32 backend
90c0b95860e [riscv64] Fix popcount
1807aa5c70c [riscv64] Fix build error
600f7533857 [riscv64] Port [fastcall] Support EnforceRange annotation
34afea56b6e [riscv64] Fix wasm-spec-tests/tests/func
74955ee1c7a [riscv64][wasm] Fix and harden all conditional tier-up checks
2e9ce2ffbf0 [riscv64] [wasm][stack-switching] Support rejected promises
f099ba84cfe [riscv64]Fix about nan error
308a7e2f58b [riscv64][liftoff] Fix implicit conversion to LiftoffRegList
643d69f75ba [riscv64] Optmize load float zero
a986dcff73b [riscv64] Avoid using callee saved register in call func
3975045cc8d [riscv64] Fix mem segment fault in simulator
ae9f9c67097 [riscv64] Implement relaxed_trunc
562160fb98b [riscv64][heap] Remove write barrier builtin for incremental marking
3af7f6add68 [riscv64][wasm-simd] Prototype relaxed integer Dot product instructions
0aef4bc7f2e [riscv64] Port Improve gap resolver algorithm
c1caada64d0 [test] Move cctest/test-disasm-riscv64 to unittests/assembler/
462b2fb5c68 [riscv64] Optimize call/jump code instr
a4f8bb5939a [riscv64] Fix name ambiguous
ee6c6a2f1c1 [riscv64] Using SystemPointerSize to index address for PrologueFillFrame
bdb20626c10 [riscv64] Fix return value of lazy compile runtime function
caa55eca659 [riscv64] Implement emit_i8x16_relaxed_swizzle
e868f793e13 [riscv64][wasm-relaxed-simd] Add liftoff min/max operations on RISCV64
2bd261c0716 [riscv64][wasm-relaxed-simd] Keep q15_mul emit operations consistent
07a76e37843 [riscv64] Implement emit_s128_relaxed_laneselect
fc2b353c65b [riscv64] fix build error
3d5e5f18e06 [riscv64] Add macro to control disassemble rvv
ee1a364f0a6 [riscv64] Implement relaxed_i16x8_q15mulr_s
1d25122aae9 [riscv64] Enable some optional machine opcodes
483400e5bc0 [riscv64] Delete kNoCondition
359c48d908a [riscv64] Delete extra scratch reg
2dfd87f2101 [riscv64] Remove the Dummy interface descriptor
8b34a965825 [riscv64] Reland "[osr] Use the new OSR cache"
e51739ddd0b [riscv64] Fix relocation attribute not loaded correctly
7a7cfa62638 [riscv64] Fix codegen error of Simd128_AndNot
4156134b5f7 [riscv64] use not equal to confirm sc whether success or not
720329fc5af [riscv64] Fix emit_u32_to_uintptr to be zero-extended
70caf337c3f [riscv64] Fix the StaticStackFrameSize

对于 vite --version 在 nodejs 18 上报错这一例子, 如果禁用 JIT 再进行尝试,

NODE_OPTIONS=--jitless node node_modules/.bin/vite --version

会得到如下报错:

Warning: disabling flag --expose_wasm due to conflicting flags

...中间省略...

ReferenceError: WebAssembly is not defined
    at file:///build/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:16497:1125
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

Node.js v18.18.0

禁用 JIT 会一并禁用 WebAssembly,这里的报错说明了 vite 或 vite 的依赖在运行时使用了 WebAssembly。

列表里按照 commit 顺序来看,第一个 commit 70caf337c3f [riscv64] Fix the StaticStackFrameSize 就是 wasm 相关的一个 Fix:

commit 70caf337c3f69b16ac9ffec0d9a776aa95f896fc
Author: Lu Yahan <yahan@iscas.ac.cn>
Date:   Thu Apr 14 11:32:59 2022 +0800

    [riscv64] Fix the StaticStackFrameSize
    
     Update the size to kTierupBudgetOffset.
    
    Change-Id: Ibe241211ef67148fae3a4a9eed271f9293ca4801
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3585492
    Reviewed-by: ji qiu <qiuji@iscas.ac.cn>
    Commit-Queue: Yahan Lu <yahan@iscas.ac.cn>
    Auto-Submit: Yahan Lu <yahan@iscas.ac.cn>
    Cr-Commit-Position: refs/heads/main@{#79978}

diff --git a/src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h b/src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h
index 642a7d2a335..8d7ef96f3ad 100644
--- a/src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h
+++ b/src/wasm/baseline/riscv64/liftoff-assembler-riscv64.h
@@ -393,7 +393,7 @@ void LiftoffAssembler::AbortCompilation() { AbortedCodeGeneration(); }
 
 // static
 constexpr int LiftoffAssembler::StaticStackFrameSize() {
-  return liftoff::kFeedbackVectorOffset;
+  return liftoff::kTierupBudgetOffset;
 }
 
 int LiftoffAssembler::SlotSizeForType(ValueKind kind) {

尝试 backport 这个 commit 到 Node.js 18, 即把这个 commit 的 patch 应用到 Node.js 18 的 deps/v8 目录下面, 然后编译,再次尝试 vite --version, bug 解决了。

对于本例而言,要 backport 的 commit 其实是这两个版本之间的第一个实质性的 commit, backport 这个 commit 不会存在把正确的 commit backport 到错误的上下文的风险, 但是对于一些更复杂的问题,可能 backport 的情形更加复杂,建议与 V8 小队进行沟通。

git log --reverse --oneline 10.2.154.26..10.7.193.13 | head -n 4
45927106d8f Update V8 DEPS.
70caf337c3f [riscv64] Fix the StaticStackFrameSize
720329fc5af [riscv64] Fix emit_u32_to_uintptr to be zero-extended
f8fddd6b13a Reland "[osr] Extract extended OSR checks to BaselineOnStackReplacement builtin"

那么我们就可以给 Node.js 提交一个 PR 进行修复了。Node.js 对于 V8 commit 的 backport 有着标准的流程, 首先安装 Node.js Core Utilities, 新版本(v4)的包名是 @node-core/utils, 但是我在使用时遇到了一些问题,所以我使用了旧版本(v3),包名是 node-core-utils

在 Node.js 的 git repo 中,基于 v18.x-staging 分支新建一个 topic 分支,

运行 git node v8 backport 70caf337c3f69b16ac9ffec0d9a776aa95f896fc 即可创建一个 v8 backport 的 commit, 然后就可以提交 PR 了。

Clone this wiki locally