diff --git a/.github/workflows/update-v8.yml b/.github/workflows/update-v8.yml index c3927da812..4dac697976 100644 --- a/.github/workflows/update-v8.yml +++ b/.github/workflows/update-v8.yml @@ -2,7 +2,7 @@ name: Update V8 on: schedule: - - cron: "1 10 * * *" # this is 1 hour after the autoroll in denoland/v8 + - cron: "0 10 * * *" workflow_dispatch: permissions: write-all diff --git a/patches/0001-Remove-googletest-visibility-workaround-in-BUILD.gn.patch b/patches/0001-Remove-googletest-visibility-workaround-in-BUILD.gn.patch new file mode 100644 index 0000000000..2eab675050 --- /dev/null +++ b/patches/0001-Remove-googletest-visibility-workaround-in-BUILD.gn.patch @@ -0,0 +1,54 @@ +From fe0790450d0c8668e859d125e952bd3687267adb Mon Sep 17 00:00:00 2001 +From: Divy Srivastava +Date: Tue, 5 Dec 2023 09:35:57 +0530 +Subject: [PATCH] Remove googletest visibility workaround in BUILD.gn + +--- + third_party/googletest/BUILD.gn | 18 ------------------ + 1 file changed, 18 deletions(-) + +diff --git a/third_party/googletest/BUILD.gn b/third_party/googletest/BUILD.gn +index 1cf84b3..0918a49 100644 +--- a/third_party/googletest/BUILD.gn ++++ b/third_party/googletest/BUILD.gn +@@ -2,8 +2,6 @@ + # Use of this source code is governed by a BSD-style license that can be + # found in the LICENSE file. + +-import("../../gni/v8.gni") +- + config("gtest_config") { + visibility = [ ":*" ] # gmock also shares this config. + +@@ -91,14 +89,6 @@ source_set("gtest") { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + +- # V8-only workaround for http://crbug.com/chromium/1191946. Ensures that +- # googletest is compiled with the same visibility such as the rest of V8, see +- # https://source.chromium.org/chromium/chromium/src/+/master:v8/gni/v8.gni +- if ((is_posix || is_fuchsia) && (v8_enable_backtrace || v8_monolithic)) { +- configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] +- configs += [ "//build/config/gcc:symbol_visibility_default" ] +- } +- + deps = [] + + if (is_fuchsia) { +@@ -143,14 +133,6 @@ source_set("gmock") { + "src/googlemock/src/gmock.cc", + ] + +- # V8-only workaround for http://crbug.com/chromium/1191946. Ensures that +- # googletest is compiled with the same visibility such as the rest of V8, see +- # https://source.chromium.org/chromium/chromium/src/+/master:v8/gni/v8.gni +- if ((is_posix || is_fuchsia) && (v8_enable_backtrace || v8_monolithic)) { +- configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] +- configs += [ "//build/config/gcc:symbol_visibility_default" ] +- } +- + public_configs = [ + ":gmock_config", + ":gtest_config", +-- +2.37.1 (Apple Git-137.1) diff --git a/patches/0002-Fix-crash-on-Apple-Silicon-when-mprotect-fails-expec.patch b/patches/0002-Fix-crash-on-Apple-Silicon-when-mprotect-fails-expec.patch new file mode 100644 index 0000000000..9267f842ac --- /dev/null +++ b/patches/0002-Fix-crash-on-Apple-Silicon-when-mprotect-fails-expec.patch @@ -0,0 +1,43 @@ +From 183144148764c4288d63639ff0a7f46e18203fa7 Mon Sep 17 00:00:00 2001 +From: Bert Belder +Date: Wed, 25 May 2022 20:40:04 +0200 +Subject: [PATCH 3/4] Fix crash on Apple Silicon when mprotect() fails + expectedly + +--- + src/base/platform/platform-posix.cc | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc +index da42cda6c4..f29d754e77 100644 +--- a/src/base/platform/platform-posix.cc ++++ b/src/base/platform/platform-posix.cc +@@ -479,12 +479,6 @@ bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) { + int prot = GetProtectionFromMemoryPermission(access); + int ret = mprotect(address, size, prot); + +- // Setting permissions can fail if the limit of VMAs is exceeded. +- // Any failure that's not OOM likely indicates a bug in the caller (e.g. +- // using an invalid mapping) so attempt to catch that here to facilitate +- // debugging of these failures. +- if (ret != 0) CHECK_EQ(ENOMEM, errno); +- + // MacOS 11.2 on Apple Silicon refuses to switch permissions from + // rwx to none. Just use madvise instead. + #if defined(V8_OS_DARWIN) +@@ -494,6 +488,12 @@ bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) { + } + #endif + ++ // Setting permissions can fail if the limit of VMAs is exceeded. ++ // Any failure that's not OOM likely indicates a bug in the caller (e.g. ++ // using an invalid mapping) so attempt to catch that here to facilitate ++ // debugging of these failures. ++ if (ret != 0) CHECK_EQ(ENOMEM, errno); ++ + if (ret == 0 && access == OS::MemoryPermission::kNoAccess) { + // This is advisory; ignore errors and continue execution. + USE(DiscardSystemPages(address, size)); + +-- +2.37.3 diff --git a/tools/auto_update_v8.ts b/tools/auto_update_v8.ts index 3322333049..138bcc14bf 100644 --- a/tools/auto_update_v8.ts +++ b/tools/auto_update_v8.ts @@ -1,66 +1,133 @@ -const V8_TRACKING_BRANCH = "14.7-lkgr-denoland"; +// V8 version to track. Update this when bumping to a new major V8 version. +const V8_VERSION = "14.7"; + +const V8_UPSTREAM = "https://chromium.googlesource.com/v8/v8.git"; +const V8_FORK = "https://github.com/denoland/v8.git"; +const UPSTREAM_LKGR = `${V8_VERSION}-lkgr`; +const DENOLAND_LKGR = `${V8_VERSION}-lkgr-denoland`; const AUTOROLL_BRANCH = "autoroll"; -function extractVersion() { +async function run( + cmd: string, + args: string[], + cwd?: string, +): Promise { + console.log("$", cmd, ...args); + const proc = new Deno.Command(cmd, { args, cwd, stdout: "piped" }); + const output = await proc.output(); + if (!output.success) { + console.error(`Failed to run ${cmd} ${args.join(" ")}`); + Deno.exit(1); + } + return output.stdout; +} + +function extractVersion(path = "./v8/include/v8-version.h"): string { const MAJOR_PREFIX = "#define V8_MAJOR_VERSION "; const MINOR_PREFIX = "#define V8_MINOR_VERSION "; const BUILD_PREFIX = "#define V8_BUILD_NUMBER "; const PATCH_PREFIX = "#define V8_PATCH_LEVEL "; - const versionDotH = Deno.readTextFileSync("./v8/include/v8-version.h"); + const versionDotH = Deno.readTextFileSync(path); const lines = versionDotH.split("\n"); - const major = parseInt(lines.find((s) => s.startsWith(MAJOR_PREFIX))! - .substring(MAJOR_PREFIX.length)); - const minor = parseInt(lines.find((s) => s.startsWith(MINOR_PREFIX))! - .substring(MINOR_PREFIX.length)); - const build = parseInt(lines.find((s) => s.startsWith(BUILD_PREFIX))! - .substring(BUILD_PREFIX.length)); - const patch = parseInt(lines.find((s) => s.startsWith(PATCH_PREFIX))! - .substring(PATCH_PREFIX.length)); + const major = parseInt( + lines.find((s) => s.startsWith(MAJOR_PREFIX))!.substring( + MAJOR_PREFIX.length, + ), + ); + const minor = parseInt( + lines.find((s) => s.startsWith(MINOR_PREFIX))!.substring( + MINOR_PREFIX.length, + ), + ); + const build = parseInt( + lines.find((s) => s.startsWith(BUILD_PREFIX))!.substring( + BUILD_PREFIX.length, + ), + ); + const patch = parseInt( + lines.find((s) => s.startsWith(PATCH_PREFIX))!.substring( + PATCH_PREFIX.length, + ), + ); return `${major}.${minor}.${build}.${patch}`; } +// Start from origin/main await run("git", ["checkout", "origin/main"]); await run("git", ["submodule", "update", "--init", "--recursive", "v8"]); const currentVersion = extractVersion(); console.log(`Starting auto update. Currently on ${currentVersion}`); -async function run( - cmd: string, - args: string[], - cwd?: string, -): Promise { - console.log("$", cmd, ...args); - const proc = new Deno.Command(cmd, { args, cwd }); - const output = await proc.output(); - if (!output.success) { - console.error(`Failed to run ${cmd} ${args.join(" ")}`); - Deno.exit(1); - } - return output.stdout; +// -- Step 1: Update the denoland/v8 fork -- +// Ensure upstream remote exists in the v8 submodule +const remotes = new TextDecoder().decode( + await run("git", ["remote"], "./v8"), +); +if (!remotes.split("\n").includes("upstream")) { + await run("git", ["remote", "add", "upstream", V8_UPSTREAM], "./v8"); +} +if (!remotes.split("\n").includes("denoland")) { + await run("git", ["remote", "add", "denoland", V8_FORK], "./v8"); } -// Update v8 submodule -await run("git", ["fetch", `origin`, V8_TRACKING_BRANCH], "./v8"); -await run("git", ["checkout", `origin/${V8_TRACKING_BRANCH}`], "./v8"); +// Fetch upstream lkgr branch +await run("git", ["fetch", "upstream", UPSTREAM_LKGR], "./v8"); +// Create the denoland branch from upstream +await run( + "git", + ["checkout", "-B", DENOLAND_LKGR, `upstream/${UPSTREAM_LKGR}`], + "./v8", +); + +// Apply patches +const patches = [...Deno.readDirSync("./patches")] + .filter((e) => e.name.endsWith(".patch")) + .map((e) => e.name) + .sort(); + +for (const patch of patches) { + const patchPath = `${Deno.cwd()}/patches/${patch}`; + console.log(`Applying patch ${patch}`); + await run("git", ["am", "-3", patchPath], "./v8"); +} + +// Check if version changed const newVersion = extractVersion(); -if (currentVersion == newVersion) { +if (currentVersion === newVersion) { console.log(`No new version available. Staying on ${newVersion}`); Deno.exit(0); } console.log(`Updated to version ${newVersion}`); +// Push the patched branch to the denoland/v8 fork +console.log("Pushing patched V8 branch to denoland/v8 fork."); +await run( + "git", + ["push", "--force", "denoland", DENOLAND_LKGR], + "./v8", +); + +// Create and push a tag +const commit = new TextDecoder().decode( + await run("git", ["rev-parse", "HEAD"], "./v8"), +).trim(); +const tag = `${newVersion}-denoland-${commit.slice(0, 20)}`; +console.log(`Creating tag ${tag}`); +await run("git", ["tag", tag], "./v8"); +await run("git", ["push", "denoland", tag], "./v8"); + +// -- Step 2: Update rusty_v8 -- + // Update V8 dependencies const depsOutput = await run("python", ["tools/update_deps.py"]); -const depNames = new TextDecoder().decode(depsOutput).split("\n").filter((x) => - x.length > 0 -).at(-1)!.split( - ",", -); +const depNames = new TextDecoder().decode(depsOutput).split("\n").filter(( + x, +) => x.length > 0).at(-1)!.split(","); // Update version in readme let readme = Deno.readTextFileSync("README.md");