Compare commits

..

No commits in common. "69264a21e63b8467523bb096455b55cb7a473355" and "9672c803907b7bebe51cfaf205b04cf76e9de5c2" have entirely different histories.

1529 changed files with 32862 additions and 17939 deletions

View File

@ -1 +1 @@
105.0.5195.52 106.0.5249.91

View File

@ -43,7 +43,9 @@ Example Caddyfile (replace `user` and `pass` accordingly):
``` ```
{ {
servers { servers {
protocols h1 h2 h3 protocol {
experimental_http3
}
} }
} }
:443, example.com :443, example.com
@ -55,9 +57,7 @@ route {
hide_via hide_via
probe_resistance probe_resistance
} }
file_server { file_server { root /var/www/html }
root /var/www/html
}
} }
``` ```
`:443` must appear first for this Caddyfile to work. For more advanced usage consider using [JSON for Caddy 2's config](https://caddyserver.com/docs/json/). `:443` must appear first for this Caddyfile to work. For more advanced usage consider using [JSON for Caddy 2's config](https://caddyserver.com/docs/json/).

12
src/.gn
View File

@ -58,7 +58,7 @@ default_args = {
# Overwrite default args declared in the Fuchsia sdk # Overwrite default args declared in the Fuchsia sdk
fuchsia_sdk_readelf_exec = fuchsia_sdk_readelf_exec =
"//third_party/llvm-build/Release+Asserts/bin/llvm-readelf" "//third_party/llvm-build/Release+Asserts/bin/llvm-readelf"
fuchsia_target_api_level = 8 fuchsia_target_api_level = 9
devtools_visibility = [ "*" ] devtools_visibility = [ "*" ]
} }
@ -68,11 +68,10 @@ default_args = {
# their includes checked for proper dependencies when you run either # their includes checked for proper dependencies when you run either
# "gn check" or "gn gen --check". # "gn check" or "gn gen --check".
no_check_targets = [ no_check_targets = [
"//headless:headless_non_renderer", # 9 errors "//headless:headless_non_renderer", # 2 errors
"//headless:headless_renderer", # 13 errors "//headless:headless_renderer", # 12 errors
"//headless:headless_shared_sources", # 4 errors "//headless:headless_shared_sources", # 2 errors
"//headless:headless_shell_browser_lib", # 10 errors "//headless:headless_shell_browser_lib", # 1 errors
"//headless:headless_shell_lib", # 10 errors
# //v8, https://crbug.com/v8/7330 # //v8, https://crbug.com/v8/7330
"//v8/src/inspector:inspector", # 20 errors "//v8/src/inspector:inspector", # 20 errors
@ -154,6 +153,7 @@ exec_script_whitelist =
"//build_overrides/build.gni", "//build_overrides/build.gni",
"//chrome/android/webapk/shell_apk/prepare_upload_dir/BUILD.gn", "//chrome/android/webapk/shell_apk/prepare_upload_dir/BUILD.gn",
"//chrome/version.gni",
# TODO(dgn): Layer violation but breaks the build otherwise, see # TODO(dgn): Layer violation but breaks the build otherwise, see
# https://crbug.com/474506. # https://crbug.com/474506.

View File

@ -71,6 +71,7 @@ Alexey Korepanov <alexkorep@gmail.com>
Alexey Kuts <kruntuid@gmail.com> Alexey Kuts <kruntuid@gmail.com>
Alexey Kuzmin <alex.s.kuzmin@gmail.com> Alexey Kuzmin <alex.s.kuzmin@gmail.com>
Alexey Kuznetsov <saturas2000@gmail.com> Alexey Kuznetsov <saturas2000@gmail.com>
Alexey Terentiev <alexeyter@gmail.com>
Alexis Brenon <brenon.alexis@gmail.com> Alexis Brenon <brenon.alexis@gmail.com>
Alexis La Goutte <alexis.lagoutte@gmail.com> Alexis La Goutte <alexis.lagoutte@gmail.com>
Alexis Menard <alexis.menard@intel.com> Alexis Menard <alexis.menard@intel.com>
@ -167,6 +168,7 @@ Bert Belder <bertbelder@gmail.com>
Bhagirathi Satpathy <bhagirathi.s@samsung.com> Bhagirathi Satpathy <bhagirathi.s@samsung.com>
Bhanukrushana Rout <b.rout@samsung.com> Bhanukrushana Rout <b.rout@samsung.com>
Biljith Jayan <billy.jayan@samsung.com> Biljith Jayan <billy.jayan@samsung.com>
Bin Liao <bin.liao@intel.com>
Boaz Sender <boaz@bocoup.com> Boaz Sender <boaz@bocoup.com>
Bobby Powers <bobbypowers@gmail.com> Bobby Powers <bobbypowers@gmail.com>
Branden Archer <bma4@zips.uakron.edu> Branden Archer <bma4@zips.uakron.edu>
@ -385,6 +387,7 @@ Gajendra Singh <wxjg68@motorola.com>
Ganesh Borle <ganesh.borle@samsung.com> Ganesh Borle <ganesh.borle@samsung.com>
Gao Chun <chun.gao@intel.com> Gao Chun <chun.gao@intel.com>
Gao Chun <gaochun.dev@gmail.com> Gao Chun <gaochun.dev@gmail.com>
Gao Sheng <gaosheng08@meituan.com>
Gao Yu <wanggao@tencent.com> Gao Yu <wanggao@tencent.com>
Gaurav Dhol <gaurav.dhol@einfochips.com> Gaurav Dhol <gaurav.dhol@einfochips.com>
Gautham Banasandra <gautham.bangalore@gmail.com> Gautham Banasandra <gautham.bangalore@gmail.com>
@ -421,6 +424,7 @@ Halton Huo <halton.huo@intel.com>
Hans Hillen <hans.hillen@gmail.com> Hans Hillen <hans.hillen@gmail.com>
Hao Li <hao.x.li@intel.com> Hao Li <hao.x.li@intel.com>
Haojian Wu <hokein.wu@gmail.com> Haojian Wu <hokein.wu@gmail.com>
Haoxuan Zhang <zhanghaoxuan.59@bytedance.com>
Hari Singh <hari.singh1@samsung.com> Hari Singh <hari.singh1@samsung.com>
Harpreet Singh Khurana <harpreet.sk@samsung.com> Harpreet Singh Khurana <harpreet.sk@samsung.com>
Harshikesh Kumar <harshikeshnobug@gmail.com> Harshikesh Kumar <harshikeshnobug@gmail.com>
@ -537,6 +541,7 @@ Jiadong Zhu <jiadong.zhu@linaro.org>
Jiahe Zhang <jiahe.zhang@intel.com> Jiahe Zhang <jiahe.zhang@intel.com>
Jiajia Qin <jiajia.qin@intel.com> Jiajia Qin <jiajia.qin@intel.com>
Jiajie Hu <jiajie.hu@intel.com> Jiajie Hu <jiajie.hu@intel.com>
Jiangzhen Hou <houjiangzhen@360.cn>
Jianjun Zhu <jianjun.zhu@intel.com> Jianjun Zhu <jianjun.zhu@intel.com>
Jianneng Zhong <muzuiget@gmail.com> Jianneng Zhong <muzuiget@gmail.com>
Jiawei Shao <jiawei.shao@intel.com> Jiawei Shao <jiawei.shao@intel.com>
@ -645,6 +650,7 @@ Kaustubh Atrawalkar <kaustubh.a@samsung.com>
Kaustubh Atrawalkar <kaustubh.ra@gmail.com> Kaustubh Atrawalkar <kaustubh.ra@gmail.com>
Ke He <ke.he@intel.com> Ke He <ke.he@intel.com>
Keeley Hammond <vertedinde@electronjs.org> Keeley Hammond <vertedinde@electronjs.org>
Keeling <liqining.keeling@bytedance.com>
Keene Pan <keenepan@linpus.com> Keene Pan <keenepan@linpus.com>
Keiichiro Nagashima <n4ag3a2sh1i@gmail.com> Keiichiro Nagashima <n4ag3a2sh1i@gmail.com>
Keita Suzuki <keitasuzuki.park@gmail.com> Keita Suzuki <keitasuzuki.park@gmail.com>
@ -795,6 +801,7 @@ Mayur Kankanwadi <mayurk.vk@samsung.com>
Md Abdullah Al Alamin <a.alamin.cse@gmail.com> Md Abdullah Al Alamin <a.alamin.cse@gmail.com>
Md. Hasanur Rashid <hasanur.r@samsung.com> Md. Hasanur Rashid <hasanur.r@samsung.com>
Md Jobed Hossain <jobed.h@samsung.com> Md Jobed Hossain <jobed.h@samsung.com>
Md Raiyan bin Sayeed <mrbsayee@uwaterloo.ca>
Md Sami Uddin <md.sami@samsung.com> Md Sami Uddin <md.sami@samsung.com>
Micha Hanselmann <micha.hanselmann@gmail.com> Micha Hanselmann <micha.hanselmann@gmail.com>
Michael Cirone <mikecirone@gmail.com> Michael Cirone <mikecirone@gmail.com>
@ -926,6 +933,7 @@ Peter Molnar <pmolnar.u-szeged@partner.samsung.com>
Peter Snyder <snyderp@gmail.com> Peter Snyder <snyderp@gmail.com>
Peter Varga <pvarga@inf.u-szeged.hu> Peter Varga <pvarga@inf.u-szeged.hu>
Peter Wong <peter.wm.wong@gmail.com> Peter Wong <peter.wm.wong@gmail.com>
Phan Quang Minh <phanquangminh217@gmail.com>
Philip Hanson <philip.hanson@intel.com> Philip Hanson <philip.hanson@intel.com>
Philipp Hancke <fippo@andyet.net> Philipp Hancke <fippo@andyet.net>
Philipp Hancke <philipp.hancke@googlemail.com> Philipp Hancke <philipp.hancke@googlemail.com>
@ -1052,11 +1060,13 @@ Sathish Kuppuswamy <sathish.kuppuswamy@intel.com>
Satoshi Matsuzaki <satoshi.matsuzaki@gmail.com> Satoshi Matsuzaki <satoshi.matsuzaki@gmail.com>
Satyajit Sahu <satyajit.sahu@amd.com> Satyajit Sahu <satyajit.sahu@amd.com>
Sayan Nayak <sayan.nayak@samsung.com> Sayan Nayak <sayan.nayak@samsung.com>
Sayan Sivakumaran <sivakusayan@gmail.com>
Scott D Phillips <scott.d.phillips@intel.com> Scott D Phillips <scott.d.phillips@intel.com>
Sean Bryant <sean@cyberwang.net> Sean Bryant <sean@cyberwang.net>
Sean DuBois <seaduboi@amazon.com> Sean DuBois <seaduboi@amazon.com>
Sebastian Amend <sebastian.amend@googlemail.com> Sebastian Amend <sebastian.amend@googlemail.com>
Sebastian Krzyszkowiak <dos@dosowisko.net> Sebastian Krzyszkowiak <dos@dosowisko.net>
Sebastjan Raspor <sebastjan.raspor1@gmail.com>
Seo Sanghyeon <sanxiyn@gmail.com> Seo Sanghyeon <sanxiyn@gmail.com>
Seokju Kwon <seokju.kwon@gmail.com> Seokju Kwon <seokju.kwon@gmail.com>
Seokho Song <0xdevssh@gmail.com> Seokho Song <0xdevssh@gmail.com>
@ -1115,6 +1125,8 @@ Sohan Jyoti Ghosh <sohanjg@chromium.org>
Sohom Datta <sohom.datta@learner.manipal.edu> Sohom Datta <sohom.datta@learner.manipal.edu>
Sohom Datta <dattasohom1@gmail.com> Sohom Datta <dattasohom1@gmail.com>
Song Fangzhen <songfangzhen@bytedance.com> Song Fangzhen <songfangzhen@bytedance.com>
Song Qinglin <songql@dingdao.com>
Song Qinglin <songqinglin@gmail.com>
Song YeWen <ffmpeg@gmail.com> Song YeWen <ffmpeg@gmail.com>
Sooho Park <sooho1000@gmail.com> Sooho Park <sooho1000@gmail.com>
Soojung Choi <crystal2840@gmail.com> Soojung Choi <crystal2840@gmail.com>
@ -1303,6 +1315,7 @@ Yoav Zilberberg <yoav.zilberberg@gmail.com>
Yong Ling <yongling@tencent.com> Yong Ling <yongling@tencent.com>
Yong Shin <sy3620@gmail.com> Yong Shin <sy3620@gmail.com>
Yong Wang <ccyongwang@tencent.com> Yong Wang <ccyongwang@tencent.com>
Yonggang Luo <luoyonggang@gmail.com>
Yongha Lee <yongha78.lee@samsung.com> Yongha Lee <yongha78.lee@samsung.com>
Yongseok Choi <yongseok.choi@navercorp.com> Yongseok Choi <yongseok.choi@navercorp.com>
Yongsheng Zhu <yongsheng.zhu@intel.com> Yongsheng Zhu <yongsheng.zhu@intel.com>
@ -1320,6 +1333,7 @@ Yuki Osaki <yuki.osaki7@gmail.com>
Yuki Tsuchiya <Yuki.Tsuchiya@sony.com> Yuki Tsuchiya <Yuki.Tsuchiya@sony.com>
Yuma Takai <tara20070827@gmail.com> Yuma Takai <tara20070827@gmail.com>
Yumikiyo Osanai <yumios.art@gmail.com> Yumikiyo Osanai <yumios.art@gmail.com>
Yumin Su <yuminsu.hi@gmail.com>
Yunchao He <yunchao.he@intel.com> Yunchao He <yunchao.he@intel.com>
Yupei Lin <yplam@yplam.com> Yupei Lin <yplam@yplam.com>
Yupei Wang <perryuwang@tencent.com> Yupei Wang <perryuwang@tencent.com>
@ -1344,6 +1358,7 @@ Zhenyu Shan <zhenyu.shan@intel.com>
Zhibo Wang <zhibo1.wang@intel.com> Zhibo Wang <zhibo1.wang@intel.com>
Zhifei Fang <facetothefate@gmail.com> Zhifei Fang <facetothefate@gmail.com>
Zhiyuan Ye <zhiyuanye@tencent.com> Zhiyuan Ye <zhiyuanye@tencent.com>
Zhou Jun <zhoujun@uniontech.com>
Zhuoyu Qian <zhuoyu.qian@samsung.com> Zhuoyu Qian <zhuoyu.qian@samsung.com>
Ziran Sun <ziran.sun@samsung.com> Ziran Sun <ziran.sun@samsung.com>
Zoltan Czirkos <czirkos.zoltan@gmail.com> Zoltan Czirkos <czirkos.zoltan@gmail.com>
@ -1431,7 +1446,9 @@ Venture 3 Systems LLC <*@venture3systems.com>
Vewd Software AS <*@vewd.com> Vewd Software AS <*@vewd.com>
Vivaldi Technologies AS <*@vivaldi.com> Vivaldi Technologies AS <*@vivaldi.com>
Wacom <*@wacom.com> Wacom <*@wacom.com>
Whist Technologies <*@whist.com>
Xperi Corporation <*@xperi.com> Xperi Corporation <*@xperi.com>
Yandex LLC <*@yandex-team.ru> Yandex LLC <*@yandex-team.ru>
Zuckjet <zuckjet@gmail.com>
# Please DO NOT APPEND here. See comments at the top of the file. # Please DO NOT APPEND here. See comments at the top of the file.
# END organizations section. # END organizations section.

294
src/DEPS
View File

@ -233,7 +233,7 @@ vars = {
# #
# CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-amd64-generic-chrome-skylab # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-amd64-generic-chrome-skylab
# CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-arm-generic-chrome-skylab # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-arm-generic-chrome-skylab
'lacros_sdk_version': '14977.0.0', 'lacros_sdk_version': '15040.0.0',
# Generate location tag metadata to include in tests result data uploaded # Generate location tag metadata to include in tests result data uploaded
# to ResultDB. This isn't needed on some configs and the tool that generates # to ResultDB. This isn't needed on some configs and the tool that generates
@ -279,7 +279,7 @@ vars = {
'dawn_standalone': False, 'dawn_standalone': False,
# reclient CIPD package version # reclient CIPD package version
'reclient_version': 're_client_version:0.72.0.b874055-gomaip', 'reclient_version': 're_client_version:0.76.0.f4c4bc4-gomaip',
# Enable fetching Rust-related packages. # Enable fetching Rust-related packages.
'use_rust': False, 'use_rust': False,
@ -297,34 +297,34 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Skia # the commit queue can handle CLs rolling Skia
# and whatever else without interference from each other. # and whatever else without interference from each other.
'skia_revision': 'f204b137b97b44b7397de173fc54181c37ac6501', 'skia_revision': 'ba6bc7d02d406a262e155a83e71cf4c19736a312',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling V8 # the commit queue can handle CLs rolling V8
# and whatever else without interference from each other. # and whatever else without interference from each other.
'v8_revision': 'b1f56b4a8a7cf9f707f7966104278777f9994b13', 'v8_revision': '69ffa9cea07d4a4177d0224c2c8fabfd0c314f2f',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ANGLE # the commit queue can handle CLs rolling ANGLE
# and whatever else without interference from each other. # and whatever else without interference from each other.
'angle_revision': '2f0d8ab049b10ee41f9b90cea8da8e80db076e38', 'angle_revision': '428b6788d71120c833f029aa4e24903fa811f77b',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling SwiftShader # the commit queue can handle CLs rolling SwiftShader
# and whatever else without interference from each other. # and whatever else without interference from each other.
'swiftshader_revision': '16e026a959f1bc80ff237aa81b4a63b52517dec1', 'swiftshader_revision': '1c3dfde53353d5e13ca25eb52aa208d450b5e980',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling PDFium # the commit queue can handle CLs rolling PDFium
# and whatever else without interference from each other. # and whatever else without interference from each other.
'pdfium_revision': 'd14da8e682e244127db32490365d1c094243e5f3', 'pdfium_revision': 'c5f61025a75118b24885f97db4ecfe7f81db462d',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL # the commit queue can handle CLs rolling BoringSSL
# and whatever else without interference from each other. # and whatever else without interference from each other.
# #
# Note this revision should be updated with # Note this revision should be updated with
# third_party/boringssl/roll_boringssl.py, not roll-dep. # third_party/boringssl/roll_boringssl.py, not roll-dep.
'boringssl_revision': 'b95124305ab15c7523d3e21437309fa5dd717ee8', 'boringssl_revision': 'adaa322b63d1bfbd1abcf4a308926a9a83a6acbe',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Fuchsia sdk # the commit queue can handle CLs rolling Fuchsia sdk
# and whatever else without interference from each other. # and whatever else without interference from each other.
'fuchsia_version': 'version:9.20220720.2.1', 'fuchsia_version': 'version:9.20220817.2.1',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling google-toolbox-for-mac # the commit queue can handle CLs rolling google-toolbox-for-mac
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -340,19 +340,19 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling lss # the commit queue can handle CLs rolling lss
# and whatever else without interference from each other. # and whatever else without interference from each other.
'lss_revision': '0d6435b731ef91d5182eaecff82ae96764222c48', 'lss_revision': 'ce877209e11aa69dcfffbd53ef90ea1d07136521',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling NaCl # the commit queue can handle CLs rolling NaCl
# and whatever else without interference from each other. # and whatever else without interference from each other.
'nacl_revision': '18d9964d47fc44f49a4c19b7ba91197ddca00c6a', 'nacl_revision': '6bb46e84a384cfd877bbd741d89b31c547944cfd',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling freetype # the commit queue can handle CLs rolling freetype
# and whatever else without interference from each other. # and whatever else without interference from each other.
'freetype_revision': '275b116b40c9d183d42242099ea9ff276985855b', 'freetype_revision': '7cd3f19f21cc9d600e3b765ef2058474d20233e2',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling freetype # the commit queue can handle CLs rolling freetype
# and whatever else without interference from each other. # and whatever else without interference from each other.
'freetype_testing_revision': '1ca0c99d25ae3b1e4c70513c1bf74643fc3dee09', 'freetype_testing_revision': 'b4d3251b9921e585b7d565f0edbcbfded0e2daf8',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling HarfBuzz # the commit queue can handle CLs rolling HarfBuzz
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -368,7 +368,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling catapult # the commit queue can handle CLs rolling catapult
# and whatever else without interference from each other. # and whatever else without interference from each other.
'catapult_revision': 'b6e934ef32e6591ad60636e3fe167d0e3e9aa5d4', 'catapult_revision': '72946313ec4f9773088a8258f7509fbeaf47465e',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libFuzzer # the commit queue can handle CLs rolling libFuzzer
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -376,7 +376,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling devtools-frontend # the commit queue can handle CLs rolling devtools-frontend
# and whatever else without interference from each other. # and whatever else without interference from each other.
'devtools_frontend_revision': 'b1ac4239dc5fffa56170e7367a03f35d2eaa223c', 'devtools_frontend_revision': 'c005e44cd0f38aea3bac8e0c723c6d89d144d7c3',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libprotobuf-mutator # the commit queue can handle CLs rolling libprotobuf-mutator
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -384,11 +384,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_build-tools_version # the commit queue can handle CLs rolling android_sdk_build-tools_version
# and whatever else without interference from each other. # and whatever else without interference from each other.
'android_sdk_build-tools_version': 'tRoD45SCi7UleQqSV7MrMQO1_e5P8ysphkCcj6z_cCQC', 'android_sdk_build-tools_version': '-VRKr36Uw8L_iFqqo9nevIBgNMggND5iWxjidyjnCgsC',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_emulator_version # the commit queue can handle CLs rolling android_sdk_emulator_version
# and whatever else without interference from each other. # and whatever else without interference from each other.
'android_sdk_emulator_version': 'gMHhUuoQRKfxr-MBn3fNNXZtkAVXtOwMwT7kfx8jkIgC', 'android_sdk_emulator_version': '9lGp8nTUCRRWGMnI_96HcKfzjnxEJKUcfvfwmA3wXNkC',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_extras_version # the commit queue can handle CLs rolling android_sdk_extras_version
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -400,11 +400,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_platform-tools_version # the commit queue can handle CLs rolling android_sdk_platform-tools_version
# and whatever else without interference from each other. # and whatever else without interference from each other.
'android_sdk_platform-tools_version': 'g7n_-r6yJd_SGRklujGB1wEt8iyr77FZTUJVS9w6O34C', 'android_sdk_platform-tools_version': 'RSI3iwryh7URLGRgJHsCvUxj092woTPnKt4pwFcJ6L8C',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_platforms_version # the commit queue can handle CLs rolling android_sdk_platforms_version
# and whatever else without interference from each other. # and whatever else without interference from each other.
'android_sdk_platforms_version': 'lL3IGexKjYlwjO_1Ga-xwxgwbE_w-lmi2Zi1uOlWUIAC', 'android_sdk_platforms_version': 'eo5KvW6UVor92LwZai8Zulc624BQZoCu-yn7wa1z_YcC',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_sources_version # the commit queue can handle CLs rolling android_sdk_sources_version
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -412,11 +412,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'dawn_revision': '1e98a9ba4a64301e0ab932e22ce989688f6cdf6c', 'dawn_revision': '972757dde41304685484a5d344398787cfd69219',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'quiche_revision': '53c94d968dd6a0cf748caf42462a0b676f95530c', 'quiche_revision': '9b5aac9172d4a50b53b557c86ee7715cf70740d1',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ios_webkit # the commit queue can handle CLs rolling ios_webkit
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -436,11 +436,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libavif # the commit queue can handle CLs rolling libavif
# and whatever else without interference from each other. # and whatever else without interference from each other.
'libavif_revision': 'dd2d67c5f976038354c0406a253e26dd2abc4632', 'libavif_revision': 'e0954237c40ff75dbc79991ea4774853ad09bed7',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling nearby # the commit queue can handle CLs rolling nearby
# and whatever else without interference from each other. # and whatever else without interference from each other.
'nearby_revision': 'd2c401112cc577fe3c5f9a11329bb557048af31a', 'nearby_revision': 'd92f1d47573427e6417e29a3e82ea7d4c34fe0b5',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling securemessage # the commit queue can handle CLs rolling securemessage
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -456,11 +456,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'libcxxabi_revision': 'b954e3e65634a9e2f7b595598a30c455f5f2eb26', 'libcxxabi_revision': '039323b945911a54cb7400da8fb14fcbb0348e97',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'libunwind_revision': '955e2ff5fbb15791fea263c1c80e1ec6b3c5ee61', 'libunwind_revision': '12726c93aa00e47e80dbd332cca8a1b4d67945ce',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -476,14 +476,14 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ffmpeg # the commit queue can handle CLs rolling ffmpeg
# and whatever else without interference from each other. # and whatever else without interference from each other.
'ffmpeg_revision': '880df5ede50a8534c8116d0d50e4bc4f3ef08a06', 'ffmpeg_revision': '42601c274d7a39f5ded391024c52ff444f144f75',
# If you change this, also update the libc++ revision in # If you change this, also update the libc++ revision in
# //buildtools/deps_revisions.gni. # //buildtools/deps_revisions.gni.
'libcxx_revision': '88bf4070487fbe9020697a2281743b91e5e29bef', 'libcxx_revision': 'db722166934ebc79a6e65e5fef9a6eae21eacb77',
# GN CIPD package version. # GN CIPD package version.
'gn_version': 'git_revision:9ef321772ecc161937db69acb346397e0ccc484d', 'gn_version': 'git_revision:0bcd37bd2b83f1a9ee17088037ebdfe6eab6d31a',
} }
# Only these hosts are allowed for dependencies in this DEPS file. # Only these hosts are allowed for dependencies in this DEPS file.
@ -634,7 +634,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_mac_universal', 'package': 'chromium/third_party/updater/chrome_mac_universal',
'version': 'RBRqNIwSXHjdZf4BVjWk8enaKIHw58aQGFDVNozlbWIC', 'version': 'jGg_naPD5ghuLToPE3ClG72iDs9GqSPF6M1LM2OhVAwC',
}, },
], ],
}, },
@ -645,7 +645,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_win_x86', 'package': 'chromium/third_party/updater/chrome_win_x86',
'version': 'tqlS-vFYsn2LVSJMwipq84EKLmwKa1XJb760NnpQL2gC', 'version': 'SEYmLOH4UqiO4plPuX52Olw1fYjReimhu8AGkSu0o6YC',
}, },
], ],
}, },
@ -656,7 +656,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_win_x86_64', 'package': 'chromium/third_party/updater/chrome_win_x86_64',
'version': 'RthX5RzppvSV7uq2P6pm2bnv6-dvoHpUIOsZFk57ZMEC', 'version': 'DlaEyhCmLI4fzB57R1aWxX9QkHXpbYK4ooGqiNLPX5AC',
}, },
], ],
}, },
@ -668,7 +668,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_mac_amd64', 'package': 'chromium/third_party/updater/chromium_mac_amd64',
'version': '7MvxvS-pmZP1iAXQoCiLI7nv4UkDiyw8PC1ycwpYWbYC', 'version': 'ekvYgaz0Q8adDlksn73Gh-sUisY5m76_4lr_0c1woM0C',
}, },
], ],
}, },
@ -680,7 +680,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_mac_arm64', 'package': 'chromium/third_party/updater/chromium_mac_arm64',
'version': 'd5lN7fzV07O4-Mu_T8TshrGQtlR9F508p9cdhchcLpYC', 'version': 'UEHK7zslk3sVEEqwqnRp9i3kNWbv1PiHuTanLbEU64wC',
}, },
], ],
}, },
@ -691,7 +691,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_win_x86', 'package': 'chromium/third_party/updater/chromium_win_x86',
'version': '8zehx-DVmaf_FplPe23acLAStf3Z7anQ3CY9LXBfvD0C', 'version': 'cotzeTxkTmIASM9Gv4ZgbdXS8yJTvhEm8foupSnIEdkC',
}, },
], ],
}, },
@ -702,7 +702,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_win_x86_64', 'package': 'chromium/third_party/updater/chromium_win_x86_64',
'version': 'KE8JnjZFOyHxUhVdRkm0IMVqlZIaYPnAOI-zxtUD4zUC', 'version': 'esNCd2d4_kSQlID8kAeNQDJgiTaXuVJ3oiky_Ma2mFUC',
}, },
], ],
}, },
@ -762,7 +762,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/chrome/test/data/safe_browsing/dmg', 'package': 'chromium/chrome/test/data/safe_browsing/dmg',
'version': 'a543ae3f0b3e67dd5a1c75f63317231a1d242912', 'version': '03TLfNQgc59nHmyWtYWJfFaUrEW8QDJJzXwm-672m-QC',
}, },
], ],
'condition': 'checkout_mac', 'condition': 'checkout_mac',
@ -773,16 +773,16 @@ deps = {
Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248', Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
'src/docs/website': { 'src/docs/website': {
'url': Var('chromium_git') + '/website.git' + '@' + '3965ba67f8d283378e6c0b64d634b91fb830a378', 'url': Var('chromium_git') + '/website.git' + '@' + '1b05569731b9b2d4f945fa3c87f3fa8a15a732e6',
}, },
'src/ios/third_party/earl_grey2/src': { 'src/ios/third_party/earl_grey2/src': {
'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '53a2982c85ac6cf802719603d037ad3be7091ebb', 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'd8ddfdbb1e4d12fb0f92ef1fceb21c6a8538cbfb',
'condition': 'checkout_ios', 'condition': 'checkout_ios',
}, },
'src/ios/third_party/edo/src': { 'src/ios/third_party/edo/src': {
'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '3d3dcee71993376f3abcf3457b046c1df6c13182', 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '101cd0562999a9b6fb6cff7c5783c1293a366acf',
'condition': 'checkout_ios', 'condition': 'checkout_ios',
}, },
@ -792,7 +792,7 @@ deps = {
}, },
'src/ios/third_party/material_components_ios/src': { 'src/ios/third_party/material_components_ios/src': {
'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '425d641798c86ab809fcb067bbb265958756af98', 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '72dcc44075ab9977db264c693eb883212584c1a0',
'condition': 'checkout_ios', 'condition': 'checkout_ios',
}, },
@ -802,7 +802,7 @@ deps = {
}, },
'src/ios/third_party/material_internationalization_ios/src': { 'src/ios/third_party/material_internationalization_ios/src': {
'url': Var('chromium_git') + '/external/github.com/material-foundation/material-internationalization-ios.git' + '@' + 'ad190b15a5e3f2d84c9b8182a3a0b84428edce68', 'url': Var('chromium_git') + '/external/github.com/material-foundation/material-internationalization-ios.git' + '@' + '305aa8d276f5137c98c5c1c888efc22e02251ee7',
'condition': 'checkout_ios', 'condition': 'checkout_ios',
}, },
@ -862,7 +862,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/rts/model/linux-amd64', 'package': 'chromium/rts/model/linux-amd64',
'version': 'XlzIsX8AH06QHVAMzpKt5aT3nfupjnBr78ztG18pXdsC', 'version': 'MHZoKHSLMgxFLr6l4cmXLh5Kl9WvlxPv08vb9doDa9YC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -873,7 +873,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/rts/model/mac-amd64', 'package': 'chromium/rts/model/mac-amd64',
'version': 'CPhzNoasDtJ45F8bwTLs7lIQDiy-PhdReFmXrlL5FDoC', 'version': 'sGVhzaqwgT697qIGKjfghO3mclJdO4I-L5nQoJqYb3sC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -884,7 +884,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/rts/model/windows-amd64', 'package': 'chromium/rts/model/windows-amd64',
'version': 'XmZtpYZGxTqwBMgEXpdyfrdCxx79QfYeVlhpviF2OUcC', 'version': 'GUeUYkTnmtlRNdQBo9biZRZks9a3yshCcUu-YqToTbkC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -895,7 +895,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'experimental/google.com/sshrimp/chromium/rts/model/linux-amd64', 'package': 'experimental/google.com/sshrimp/chromium/rts/model/linux-amd64',
'version': '3K1dz8hGV_xBeEcPKmXfrPYWCwXdRf6KVVLrg7AuJ0sC', 'version': '61RZ40XmEInOMhnIJMEqdOjocdCHqodmEJcDxu4x7uIC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -952,7 +952,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/androidx', 'package': 'chromium/third_party/androidx',
'version': 'gAsD4l8EoP_W0IH5vzedZ1tyN3-wAP8-fqkaS_mX6rcC', 'version': 'nJRbqGtdXzotJnB8kFaAckjFBKzXW4O9BdApCCC7J8AC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -974,7 +974,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_system_sdk/public', 'package': 'chromium/third_party/android_system_sdk/public',
'version': 'oSfDIvHlCa6W0gS79Q5OOfB9E4eBg3uAvi3BEDN21U0C', 'version': 'RGY8Vyf8jjszRIJRFxZj7beXSUEHTQM90MtYejUvdMgC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -985,7 +985,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/aapt2', 'package': 'chromium/third_party/android_build_tools/aapt2',
'version': 'hf9C5IyJUUGaBnzqu60xiFJSyfAmjqjc_PiNXNVc9l0C', 'version': 'nSnWUNu6ssPA-kPMvFQj4JjDXRWj2iubvvjfT1F6HCMC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1007,7 +1007,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/lint', 'package': 'chromium/third_party/android_build_tools/lint',
'version': 'INnGGTfg5gGJutJiBtWI6-QwusHDDnKvZzI53Q3UiecC', 'version': 'nklp_LHwFqk9tuQm1yHGBy2W16YMz_R7Q7vcnZZnF78C',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1018,7 +1018,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/manifest_merger', 'package': 'chromium/third_party/android_build_tools/manifest_merger',
'version': '0WkAedh1tJB8lzisWJRT80UjpacKLltuV7NqP-0tx9gC', 'version': 'CvokX4c6dx7DwQ8VVMQ70CROzyJWg13oOq3feeuTzg8C',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1033,7 +1033,7 @@ deps = {
'src/third_party/android_sdk/public': { 'src/third_party/android_sdk/public': {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_sdk/public/build-tools/31.0.0', 'package': 'chromium/third_party/android_sdk/public/build-tools/33.0.0',
'version': Var('android_sdk_build-tools_version'), 'version': Var('android_sdk_build-tools_version'),
}, },
{ {
@ -1049,7 +1049,7 @@ deps = {
'version': Var('android_sdk_platform-tools_version'), 'version': Var('android_sdk_platform-tools_version'),
}, },
{ {
'package': 'chromium/third_party/android_sdk/public/platforms/android-31', 'package': 'chromium/third_party/android_sdk/public/platforms/android-33',
'version': Var('android_sdk_platforms_version'), 'version': Var('android_sdk_platforms_version'),
}, },
{ {
@ -1069,7 +1069,7 @@ deps = {
Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'), Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'),
'src/third_party/content_analysis_sdk/src': 'src/third_party/content_analysis_sdk/src':
Var('chromium_git') + '/external/github.com/chromium/content_analysis_sdk.git' + '@' + '1d7dd0490808a8a972949521cc314e42d085c69f', Var('chromium_git') + '/external/github.com/chromium/content_analysis_sdk.git' + '@' + 'fe3c222acb75bdd5248a3339d4255f032e293296',
'src/third_party/dav1d/libdav1d': 'src/third_party/dav1d/libdav1d':
Var('chromium_git') + '/external/github.com/videolan/dav1d.git' + '@' + '87f9a81cd770e49394a45deca7a3df41243de00b', Var('chromium_git') + '/external/github.com/videolan/dav1d.git' + '@' + '87f9a81cd770e49394a45deca7a3df41243de00b',
@ -1078,7 +1078,7 @@ deps = {
Var('dawn_git') + '/dawn.git' + '@' + Var('dawn_revision'), Var('dawn_git') + '/dawn.git' + '@' + Var('dawn_revision'),
'src/third_party/libjxl/src': 'src/third_party/libjxl/src':
Var('chromium_git') + '/external/gitlab.com/wg1/jpeg-xl.git' + '@' + Var('libjxl_revision'), Var('chromium_git') + '/external/github.com/libjxl/libjxl.git' + '@' + Var('libjxl_revision'),
'src/third_party/highway/src': 'src/third_party/highway/src':
Var('chromium_git') + '/external/github.com/google/highway.git' + '@' + Var('highway_revision'), Var('chromium_git') + '/external/github.com/google/highway.git' + '@' + Var('highway_revision'),
@ -1102,7 +1102,7 @@ deps = {
Var('boringssl_git') + '/boringssl.git' + '@' + Var('boringssl_revision'), Var('boringssl_git') + '/boringssl.git' + '@' + Var('boringssl_revision'),
'src/third_party/breakpad/breakpad': 'src/third_party/breakpad/breakpad':
Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'c4c43b80ea8854c57a4374ac32579b577172dc23', Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'e085b3b50bde862d0cf3ce4594e3f391bcf5faec',
'src/third_party/byte_buddy': { 'src/third_party/byte_buddy': {
'packages': [ 'packages': [
@ -1127,7 +1127,7 @@ deps = {
}, },
'src/third_party/cast_core/public/src': 'src/third_party/cast_core/public/src':
Var('chromium_git') + '/cast_core/public' + '@' + '8ba5ff47563d0ca8233e8fa009377ed14a560cf4', Var('chromium_git') + '/cast_core/public' + '@' + '469e045e514c09701ab674d023cbaa6562866f83',
'src/third_party/catapult': 'src/third_party/catapult':
Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'), Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),
@ -1156,7 +1156,7 @@ deps = {
# Tools used when building Chrome for Chrome OS. This affects both the Simple # Tools used when building Chrome for Chrome OS. This affects both the Simple
# Chrome workflow, as well as the chromeos-chrome ebuild. # Chrome workflow, as well as the chromeos-chrome ebuild.
'src/third_party/chromite': { 'src/third_party/chromite': {
'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '60350fcfeb0bca00eba2794f53661a1b996a79a5', 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b6181b487cea5df8b340f5ab040d3c8a04c8b518',
'condition': 'checkout_chromeos', 'condition': 'checkout_chromeos',
}, },
@ -1167,14 +1167,14 @@ deps = {
Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
'src/third_party/cpuinfo/src': 'src/third_party/cpuinfo/src':
Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + 'b40bae27785787b6dd70788986fd96434cf90ae2', Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + 'beb46ca0319882f262e682dd596880c92830687f',
'src/third_party/crc32c/src': 'src/third_party/crc32c/src':
Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'fa5ade41ee480003d9c5af6f43567ba22e4e17e6', Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'fa5ade41ee480003d9c5af6f43567ba22e4e17e6',
# For Linux and Chromium OS. # For Linux and Chromium OS.
'src/third_party/cros_system_api': { 'src/third_party/cros_system_api': {
'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'f3b1373caf7bd717be4f0d21ab8c738c6bfcf418', 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '354de5ff0d73b10dbd42ecfaf393dbd26ec62bee',
'condition': 'checkout_linux', 'condition': 'checkout_linux',
}, },
@ -1184,7 +1184,7 @@ deps = {
}, },
'src/third_party/depot_tools': 'src/third_party/depot_tools':
Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0ba2fd429dd6db431fcbee6995c1278d2a3657a0', Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd14f65eba90cc352b76ff0743a307ce22450d823',
'src/third_party/devtools-frontend/src': 'src/third_party/devtools-frontend/src':
Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@ -1193,7 +1193,7 @@ deps = {
Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d', Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d',
'src/third_party/eigen3/src': 'src/third_party/eigen3/src':
Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '0e187141679fdb91da33249d18cb79a011c0e2ea', Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '34780d8bd13d0af0cf17a22789ef286e8512594d',
'src/third_party/emoji-metadata/src': { 'src/third_party/emoji-metadata/src': {
'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '8de89a7a36cd024dcd30ac9f67f3f02c37a7c8fb', 'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '8de89a7a36cd024dcd30ac9f67f3f02c37a7c8fb',
@ -1236,7 +1236,7 @@ deps = {
Var('chromium_git') + '/external/github.com/google/gemmlowp.git' + '@' + '13d57703abca3005d97b19df1f2db731607a7dc2', Var('chromium_git') + '/external/github.com/google/gemmlowp.git' + '@' + '13d57703abca3005d97b19df1f2db731607a7dc2',
'src/third_party/grpc/src': { 'src/third_party/grpc/src': {
'url': Var('chromium_git') + '/external/github.com/grpc/grpc.git' + '@' + '89f7534e43cf73f56c492a9cf7eb85ca6bfbd87a', 'url': Var('chromium_git') + '/external/github.com/grpc/grpc.git' + '@' + 'dd77c67217b10ffeaf766e25eb8b46d2d59de4ff',
}, },
'src/third_party/freetype/src': 'src/third_party/freetype/src':
@ -1338,7 +1338,7 @@ deps = {
Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '41cdffd71c9948f63c7ad36e1fb0ff519aa7a37e', Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '41cdffd71c9948f63c7ad36e1fb0ff519aa7a37e',
'src/third_party/icu': 'src/third_party/icu':
Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '6e558942cc8b83e525bdabaf987e06af8a377314', Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '3e03346162e9bdd41850a1184d2713da4add719e',
'src/third_party/icu4j': { 'src/third_party/icu4j': {
'packages': [ 'packages': [
@ -1378,17 +1378,6 @@ deps = {
'condition': 'checkout_android or checkout_linux', 'condition': 'checkout_android or checkout_linux',
'dep_type': 'cipd', 'dep_type': 'cipd',
}, },
'src/third_party/jdk/extras': {
'packages': [
{
'package': 'chromium/third_party/jdk/extras',
'version': '-7m_pvgICYN60yQI3qmTj_8iKjtnT4NXicT0G_jJPqsC',
},
],
# Needed on Linux for use on chromium_presubmit (for checkstyle).
'condition': 'checkout_android or checkout_linux',
'dep_type': 'cipd',
},
'src/third_party/jsoncpp/source': 'src/third_party/jsoncpp/source':
Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git'
@ -1409,7 +1398,7 @@ deps = {
Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'df35d6c42da4fa2759e4cfb592afe33817993b89', Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'df35d6c42da4fa2759e4cfb592afe33817993b89',
'src/third_party/libaom/source/libaom': 'src/third_party/libaom/source/libaom':
Var('aomedia_git') + '/aom.git' + '@' + '8dcdafc6d4a2f9f8ea8104f26eca5d123eefcb7f', Var('aomedia_git') + '/aom.git' + '@' + '5bd38c95006adc1b3b9523a6980207c5576fd8a5',
'src/third_party/libavif/src': 'src/third_party/libavif/src':
Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'), Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'),
@ -1447,7 +1436,7 @@ deps = {
}, },
'src/third_party/libphonenumber/dist': 'src/third_party/libphonenumber/dist':
Var('chromium_git') + '/external/libphonenumber.git' + '@' + '68eba9d6ee8b11fb58ece36b6c46d07965d7f7ff', Var('chromium_git') + '/external/libphonenumber.git' + '@' + '140dfeb81b753388e8a672900fb7a971e9a0d362',
'src/third_party/libprotobuf-mutator/src': 'src/third_party/libprotobuf-mutator/src':
Var('chromium_git') + '/external/github.com/google/libprotobuf-mutator.git' + '@' + Var('libprotobuf-mutator'), Var('chromium_git') + '/external/github.com/google/libprotobuf-mutator.git' + '@' + Var('libprotobuf-mutator'),
@ -1467,7 +1456,7 @@ deps = {
}, },
'src/third_party/libvpx/source/libvpx': 'src/third_party/libvpx/source/libvpx':
Var('chromium_git') + '/webm/libvpx.git' + '@' + '711bef67400f096416cb1ba7f6560e533871490f', Var('chromium_git') + '/webm/libvpx.git' + '@' + '8786aee5821801fe6b5a285be009ba67ea7f4e63',
'src/third_party/libwebm/source': 'src/third_party/libwebm/source':
Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da', Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da',
@ -1476,7 +1465,7 @@ deps = {
Var('chromium_git') + '/webm/libwebp.git' + '@' + '7366f7f394af26de814296152c50e673ed0a832f', Var('chromium_git') + '/webm/libwebp.git' + '@' + '7366f7f394af26de814296152c50e673ed0a832f',
'src/third_party/libyuv': 'src/third_party/libyuv':
Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'd248929c059ff7629a85333699717d7a677d8d96', Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '65e7c9d5706a77d1949da59bfcb0817c252ef8d6',
'src/third_party/lighttpd': { 'src/third_party/lighttpd': {
'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'), 'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'),
@ -1488,6 +1477,28 @@ deps = {
'condition': 'checkout_android or checkout_linux', 'condition': 'checkout_android or checkout_linux',
}, },
'src/third_party/lzma_sdk/bin/host_platform': {
'packages': [
{
'package': 'infra/3pp/tools/7z/${{platform}}',
'version': 'version:2@22.01',
},
],
'condition': 'checkout_win',
'dep_type': 'cipd',
},
'src/third_party/lzma_sdk/bin/win64': {
'packages': [
{
'package': 'infra/3pp/tools/7z/windows-amd64',
'version': 'version:2@22.01',
},
],
'condition': 'checkout_win',
'dep_type': 'cipd',
},
'src/third_party/material_design_icons/src': { 'src/third_party/material_design_icons/src': {
'url': Var('chromium_git') + '/external/github.com/google/material-design-icons.git' + '@' + 'url': Var('chromium_git') + '/external/github.com/google/material-design-icons.git' + '@' +
'5ab428852e35dc177a8c37a2df9dc9ccf768c65a', '5ab428852e35dc177a8c37a2df9dc9ccf768c65a',
@ -1567,7 +1578,7 @@ deps = {
Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6', Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6',
'src/third_party/openscreen/src': 'src/third_party/openscreen/src':
Var('chromium_git') + '/openscreen' + '@' + '6be6b78224a276e908b8272542d125e133c40f3f', Var('chromium_git') + '/openscreen' + '@' + '7f795b08c7e41abdecab742d1577cf22c40dadd7',
'src/third_party/openxr/src': { 'src/third_party/openxr/src': {
'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245', 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245',
@ -1584,7 +1595,7 @@ deps = {
}, },
'src/third_party/perfetto': 'src/third_party/perfetto':
Var('android_git') + '/platform/external/perfetto.git' + '@' + '361efbf9aab595e4dfa79ec48f242d9e722393c9', Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c16f31c6da7523528ae09808c3427fb395142c94',
'src/third_party/perl': { 'src/third_party/perl': {
'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@ -1594,17 +1605,6 @@ deps = {
'src/third_party/pthreadpool/src': 'src/third_party/pthreadpool/src':
Var('chromium_git') + '/external/github.com/Maratyszcza/pthreadpool.git' + '@' + '1787867f6183f056420e532eec640cba25efafea', Var('chromium_git') + '/external/github.com/Maratyszcza/pthreadpool.git' + '@' + '1787867f6183f056420e532eec640cba25efafea',
'src/third_party/proguard': {
'packages': [
{
'package': 'chromium/third_party/proguard',
'version': 'Fd91BJFVlmiO6c46YMTsdy7n2f5Sk2hVVGlzPLvqZPsC',
},
],
'condition': 'checkout_android',
'dep_type': 'cipd',
},
# Dependency of skia. # Dependency of skia.
'src/third_party/pyelftools': { 'src/third_party/pyelftools': {
'url': Var('chromium_git') + '/chromiumos/third_party/pyelftools.git' + '@' + '19b3e610c86fcadb837d252c794cb5e8008826ae', 'url': Var('chromium_git') + '/chromiumos/third_party/pyelftools.git' + '@' + '19b3e610c86fcadb837d252c794cb5e8008826ae',
@ -1629,13 +1629,13 @@ deps = {
}, },
'src/third_party/re2/src': 'src/third_party/re2/src':
Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'ba2e7c2f25047a6848f2baa9bc4cb700ea9dda84', Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '2013ae0f998304d69fe36a0164845dca2643a718',
'src/third_party/r8': { 'src/third_party/r8': {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/r8', 'package': 'chromium/third_party/r8',
'version': 'auReXfxxD74XGdPdi-rYsKrp4sRwYwgNjh_W0PT7vNcC', 'version': 'qvL35O3yU1ZbOWHVZBedmVtdaav1qKquii4RJyUh-PgC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1651,7 +1651,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/robolectric', 'package': 'chromium/third_party/robolectric',
'version': 'WZ96VJuhBM63xzHb-_E72Tf46M9yIbfia6basI1YG4EC', 'version': '6OaDTPaXu0VZoMwWllgaXTeiaJR5jQkZb1_aooRa2GUC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1659,7 +1659,7 @@ deps = {
}, },
'src/third_party/ruy/src': 'src/third_party/ruy/src':
Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '72155b3185246e9143f4c6a3a7f283d2ebba8524', Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '841ea4172ba904fe3536789497f9565f2ef64129',
'src/third_party/skia': 'src/third_party/skia':
Var('skia_git') + '/skia.git' + '@' + Var('skia_revision'), Var('skia_git') + '/skia.git' + '@' + Var('skia_revision'),
@ -1671,7 +1671,7 @@ deps = {
Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + '65dc7b383985eb4f63cd3e752136db8d9b4be8c0', Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + '65dc7b383985eb4f63cd3e752136db8d9b4be8c0',
'src/third_party/sqlite/src': 'src/third_party/sqlite/src':
Var('chromium_git') + '/chromium/deps/sqlite.git' + '@' + 'e6b63421941617bf5ccac6b4a62d7a7b4a2c3fef', Var('chromium_git') + '/chromium/deps/sqlite.git' + '@' + '5fb64c1a111a36e7530a8d2132e6ce0c46607942',
'src/third_party/sqlite4java': { 'src/third_party/sqlite4java': {
'packages': [ 'packages': [
@ -1702,7 +1702,7 @@ deps = {
Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
'src/third_party/tflite/src': 'src/third_party/tflite/src':
Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'ac31ffa987c14665062c00f98ec025a3fdc185ab', Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '20bdb50879599c0e7a62036ee3fd8a644ced97f1',
'src/third_party/turbine': { 'src/third_party/turbine': {
'packages': [ 'packages': [
@ -1715,7 +1715,7 @@ deps = {
'dep_type': 'cipd', 'dep_type': 'cipd',
}, },
'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@c42337d9ef75170244486b580bad7dfe78447bfd', 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@31a5e38f3e48d6706f5ccb2d2b74eeda1de6a21a',
'src/third_party/vulkan_memory_allocator': 'src/third_party/vulkan_memory_allocator':
Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@ -1728,7 +1728,7 @@ deps = {
# Wayland protocols that add functionality not available in the core protocol. # Wayland protocols that add functionality not available in the core protocol.
'src/third_party/wayland-protocols/src': { 'src/third_party/wayland-protocols/src': {
'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/wayland-protocols.git' + '@' + 'd324986823519c15b2162fc3e0a720f349e43b0c', 'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/wayland-protocols.git' + '@' + '83866f19d3d61b28e94d71781646466b3a6623d8',
'condition': 'checkout_linux', 'condition': 'checkout_linux',
}, },
@ -1751,10 +1751,10 @@ deps = {
Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '44e4c8770158c505b03ee7feafa4859d083b0912', Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '44e4c8770158c505b03ee7feafa4859d083b0912',
'src/third_party/webgpu-cts/src': 'src/third_party/webgpu-cts/src':
Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'c4eb1df3f306c0ee3e43ba2446eb3616e42d6855', Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '4e8df07a22cac3a9a4b606c7458ecb4646fabf73',
'src/third_party/webrtc': 'src/third_party/webrtc':
Var('webrtc_git') + '/src.git' + '@' + 'dc5cf31cad576376abd3aa6306169453cfd85ba5', Var('webrtc_git') + '/src.git' + '@' + '17f085c1d7f6f0cad9e6041aa55a22594925eca5',
'src/third_party/libgifcodec': 'src/third_party/libgifcodec':
Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'),
@ -1775,7 +1775,7 @@ deps = {
}, },
'src/third_party/xnnpack/src': 'src/third_party/xnnpack/src':
Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'a33b227047def29b79853ef688b6dda6c6fc5386', Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '8e3d3359f9bec608e09fac1f7054a2a14b1bd73c',
'src/tools/page_cycler/acid3': 'src/tools/page_cycler/acid3':
Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521', Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521',
@ -1784,7 +1784,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/linux-amd64', 'package': 'skia/tools/goldctl/linux-amd64',
'version': 'BquSeorcTU84O2_A8IoWetGrcfLWxLfZCo9sve1Wt2IC', 'version': 'ebDbf3X2jdAICDlXMXUr7yp4muhSvYoREDLdZZoJzuAC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1794,7 +1794,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/windows-amd64', 'package': 'skia/tools/goldctl/windows-amd64',
'version': 'AOoQr1u4-cOIEYJDAgVxGWoTiPaRcjrSsjjAaB-u_ggC', 'version': '58nNno6pNLLSJaZknYmuijuo5gy2tfRBKNI1iCldDlcC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1805,7 +1805,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/mac-amd64', 'package': 'skia/tools/goldctl/mac-amd64',
'version': '-t3YY_sZ-jtMAYZ2PlhjudFnEUgk4m-HjlIwSip4tOAC', 'version': 'yE_XL6pbQ8M0WuI236ObRlkSxu0XMdWs_AnUeo21wa8C',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1816,7 +1816,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/mac-arm64', 'package': 'skia/tools/goldctl/mac-arm64',
'version': 'x_xKUnqrgizoTO8mxX4RkyhpQ-nUp_x_go9YH-tc--QC', 'version': 'l46gUmkc-2-OsEMo-oEbpXiBAYg48KtXbtF1lyBh0u8C',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1827,7 +1827,7 @@ deps = {
Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'),
'src-internal': { 'src-internal': {
'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c29563eac12bc062b66805a4766673729ce7d4ef', 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fa84529d9b58900f7476a217edf9dfbf8ac19b95',
'condition': 'checkout_src_internal', 'condition': 'checkout_src_internal',
}, },
@ -1846,7 +1846,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/eche_app/app', 'package': 'chromeos_internal/apps/eche_app/app',
'version': 'PEjYa5GVISxpuqCZfq9pZ3QeSWhNtWSdQ6gmJ8bizQ0C', 'version': 'uWK-hoCeXK1wUicxHb7YlPKmGDebjbXvVHcCkFbCnFkC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1857,7 +1857,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/help_app/app', 'package': 'chromeos_internal/apps/help_app/app',
'version': 'MqUROEBmHZCBRsEY3abQ7JOvoDr5wZ_MTK3vAN-901wC', 'version': '_JqbtCltJUQrGFSIw_3hlkjdvrFVrqIKXh9aSzVJ0e8C',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1868,7 +1868,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/media_app/app', 'package': 'chromeos_internal/apps/media_app/app',
'version': 'tV1aN61vvzGiDSJgQxN_namEG8pvO6RTuO-qbQMC51IC', 'version': 'OUGohHk5YvTdODZGYUatmAIbkUeI9qX41jPUFsn8kFAC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1879,7 +1879,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/projector_app/app', 'package': 'chromeos_internal/apps/projector_app/app',
'version': 'Eeqz2JXdGXA3-P7iu9xSzSc3iyUuAruoN1W3-FplxR4C', 'version': 'xbs9VsAB3uK9gNyQtNWmfxYtOUrdR28ynajJYzrV6tAC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -2671,7 +2671,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/com_google_android_material_material', 'package': 'chromium/third_party/android_deps/libs/com_google_android_material_material',
'version': 'version:2@1.6.0-alpha01.cr1', 'version': 'version:2@1.7.0-alpha02.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3309,7 +3309,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib', 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib',
'version': 'version:2@1.7.0.cr1', 'version': 'version:2@1.7.10.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3320,7 +3320,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common', 'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_common',
'version': 'version:2@1.7.0.cr1', 'version': 'version:2@1.7.10.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3463,7 +3463,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_annotations', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_annotations',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3474,7 +3474,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_junit', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_junit',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3485,7 +3485,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_nativeruntime', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_nativeruntime',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3496,7 +3496,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_pluginapi', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_pluginapi',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3507,7 +3507,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_plugins_maven_dependency_resolver', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_plugins_maven_dependency_resolver',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3518,7 +3518,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_resources', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_resources',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3529,7 +3529,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_robolectric', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_robolectric',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3540,7 +3540,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_sandbox', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_sandbox',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3551,7 +3551,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadowapi', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadowapi',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3562,7 +3562,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_framework', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_framework',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3573,7 +3573,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_multidex', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_multidex',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3584,7 +3584,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_playservices', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_playservices',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3595,7 +3595,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_utils', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_utils',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3606,7 +3606,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_deps/libs/org_robolectric_utils_reflector', 'package': 'chromium/third_party/android_deps/libs/org_robolectric_utils_reflector',
'version': 'version:2@4.7.3.cr1', 'version': 'version:2@4.8.1.cr1',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -3686,6 +3686,20 @@ skip_child_includes = [
hooks = [ hooks = [
# Download and initialize "vpython" VirtualEnv environment packages for
# Python2. We do this before running any other hooks so that any other
# hooks that might use vpython don't trip over unexpected issues and
# don't run slower than they might otherwise need to.
{
'name': 'vpython_common',
'pattern': '.',
# TODO(https://crbug.com/1205263): Run this on mac/arm too once it works.
'condition': 'not (host_os == "mac" and host_cpu == "arm64") and enable_vpython_common_crbug_1329052',
'action': [ 'vpython',
'-vpython-spec', 'src/.vpython',
'-vpython-tool', 'install',
],
},
# Download and initialize "vpython" VirtualEnv environment packages for # Download and initialize "vpython" VirtualEnv environment packages for
# Python3. We do this before running any other hooks so that any other # Python3. We do this before running any other hooks so that any other
# hooks that might use vpython don't trip over unexpected issues and # hooks that might use vpython don't trip over unexpected issues and
@ -4364,18 +4378,6 @@ hooks = [
'--gs_url_base=chromeos-prebuilt/afdo-job/llvm', '--gs_url_base=chromeos-prebuilt/afdo-job/llvm',
], ],
}, },
{
'name': 'gvr_static_shim_android_arm_1',
'pattern': '\\.sha1',
'condition': 'checkout_android',
'action': [ 'python3',
'src/third_party/depot_tools/download_from_google_storage.py',
'--no_resume',
'--no_auth',
'--bucket', 'chromium-gvr-static-shim',
'-s', 'src/third_party/gvr-android-sdk/libgvr_shim_static_arm_1.a.sha1',
],
},
{ {
'name': 'gvr_static_shim_android_arm_Cr', 'name': 'gvr_static_shim_android_arm_Cr',
'pattern': '\\.sha1', 'pattern': '\\.sha1',
@ -4388,18 +4390,6 @@ hooks = [
'-s', 'src/third_party/gvr-android-sdk/libgvr_shim_static_arm_Cr.a.sha1', '-s', 'src/third_party/gvr-android-sdk/libgvr_shim_static_arm_Cr.a.sha1',
], ],
}, },
{
'name': 'gvr_static_shim_android_arm64_1',
'pattern': '\\.sha1',
'condition': 'checkout_android',
'action': [ 'python3',
'src/third_party/depot_tools/download_from_google_storage.py',
'--no_resume',
'--no_auth',
'--bucket', 'chromium-gvr-static-shim',
'-s', 'src/third_party/gvr-android-sdk/libgvr_shim_static_arm64_1.a.sha1',
],
},
{ {
'name': 'gvr_static_shim_android_arm64_Cr', 'name': 'gvr_static_shim_android_arm64_Cr',
'pattern': '\\.sha1', 'pattern': '\\.sha1',

View File

@ -187,10 +187,17 @@ mixed_component("base") {
"allocator/allocator_check.h", "allocator/allocator_check.h",
"allocator/allocator_extension.cc", "allocator/allocator_extension.cc",
"allocator/allocator_extension.h", "allocator/allocator_extension.h",
"allocator/dispatcher/configuration.h",
"allocator/dispatcher/dispatcher.cc", "allocator/dispatcher/dispatcher.cc",
"allocator/dispatcher/dispatcher.h", "allocator/dispatcher/dispatcher.h",
"allocator/dispatcher/initializer.h",
"allocator/dispatcher/internal/dispatch_data.cc",
"allocator/dispatcher/internal/dispatch_data.h",
"allocator/dispatcher/internal/dispatcher_internal.h",
"allocator/dispatcher/internal/tools.h",
"allocator/dispatcher/reentry_guard.cc", "allocator/dispatcher/reentry_guard.cc",
"allocator/dispatcher/reentry_guard.h", "allocator/dispatcher/reentry_guard.h",
"allocator/dispatcher/subsystem.h",
"as_const.h", "as_const.h",
"at_exit.cc", "at_exit.cc",
"at_exit.h", "at_exit.h",
@ -348,6 +355,7 @@ mixed_component("base") {
"files/scoped_temp_dir.cc", "files/scoped_temp_dir.cc",
"files/scoped_temp_dir.h", "files/scoped_temp_dir.h",
"format_macros.h", "format_macros.h",
"functional/function_ref.h",
"functional/identity.h", "functional/identity.h",
"functional/invoke.h", "functional/invoke.h",
"functional/not_fn.h", "functional/not_fn.h",
@ -540,6 +548,10 @@ mixed_component("base") {
"power_monitor/power_monitor_source.cc", "power_monitor/power_monitor_source.cc",
"power_monitor/power_monitor_source.h", "power_monitor/power_monitor_source.h",
"power_monitor/power_observer.h", "power_monitor/power_observer.h",
"power_monitor/sampling_event_source.cc",
"power_monitor/sampling_event_source.h",
"power_monitor/timer_sampling_event_source.cc",
"power_monitor/timer_sampling_event_source.h",
"process/environment_internal.cc", "process/environment_internal.cc",
"process/environment_internal.h", "process/environment_internal.h",
"process/kill.cc", "process/kill.cc",
@ -617,6 +629,7 @@ mixed_component("base") {
"sequence_checker_impl.h", "sequence_checker_impl.h",
"sequence_token.cc", "sequence_token.cc",
"sequence_token.h", "sequence_token.h",
"state_transitions.h",
"stl_util.h", "stl_util.h",
"strings/abseil_string_conversions.cc", "strings/abseil_string_conversions.cc",
"strings/abseil_string_conversions.h", "strings/abseil_string_conversions.h",
@ -688,6 +701,8 @@ mixed_component("base") {
"task/common/checked_lock.h", "task/common/checked_lock.h",
"task/common/checked_lock_impl.cc", "task/common/checked_lock_impl.cc",
"task/common/checked_lock_impl.h", "task/common/checked_lock_impl.h",
"task/common/lazy_now.cc",
"task/common/lazy_now.h",
"task/common/operations_controller.cc", "task/common/operations_controller.cc",
"task/common/operations_controller.h", "task/common/operations_controller.h",
"task/common/scoped_defer_task_posting.cc", "task/common/scoped_defer_task_posting.cc",
@ -721,9 +736,9 @@ mixed_component("base") {
"task/sequence_manager/enqueue_order_generator.h", "task/sequence_manager/enqueue_order_generator.h",
"task/sequence_manager/fence.cc", "task/sequence_manager/fence.cc",
"task/sequence_manager/fence.h", "task/sequence_manager/fence.h",
"task/sequence_manager/hierarchical_timing_wheel.cc",
"task/sequence_manager/hierarchical_timing_wheel.h",
"task/sequence_manager/lazily_deallocated_deque.h", "task/sequence_manager/lazily_deallocated_deque.h",
"task/sequence_manager/lazy_now.cc",
"task/sequence_manager/lazy_now.h",
"task/sequence_manager/sequence_manager.cc", "task/sequence_manager/sequence_manager.cc",
"task/sequence_manager/sequence_manager.h", "task/sequence_manager/sequence_manager.h",
"task/sequence_manager/sequence_manager_impl.cc", "task/sequence_manager/sequence_manager_impl.cc",
@ -752,6 +767,8 @@ mixed_component("base") {
"task/sequence_manager/thread_controller_with_message_pump_impl.h", "task/sequence_manager/thread_controller_with_message_pump_impl.h",
"task/sequence_manager/time_domain.cc", "task/sequence_manager/time_domain.cc",
"task/sequence_manager/time_domain.h", "task/sequence_manager/time_domain.h",
"task/sequence_manager/timing_wheel.cc",
"task/sequence_manager/timing_wheel.h",
"task/sequence_manager/wake_up_queue.cc", "task/sequence_manager/wake_up_queue.cc",
"task/sequence_manager/wake_up_queue.h", "task/sequence_manager/wake_up_queue.h",
"task/sequence_manager/work_deduplicator.cc", "task/sequence_manager/work_deduplicator.cc",
@ -1047,6 +1064,12 @@ mixed_component("base") {
"message_loop/message_pump_win.cc", "message_loop/message_pump_win.cc",
"message_loop/message_pump_win.h", "message_loop/message_pump_win.h",
"native_library_win.cc", "native_library_win.cc",
"power_monitor/battery_level_provider.cc",
"power_monitor/battery_level_provider.h",
"power_monitor/battery_level_provider_win.cc",
"power_monitor/power_monitor_device_source_win.cc",
"power_monitor/speed_limit_observer_win.cc",
"power_monitor/speed_limit_observer_win.h",
"process/kill_win.cc", "process/kill_win.cc",
"process/launch_win.cc", "process/launch_win.cc",
"process/memory_win.cc", "process/memory_win.cc",
@ -1097,6 +1120,8 @@ mixed_component("base") {
"win/core_winrt_util.cc", "win/core_winrt_util.cc",
"win/core_winrt_util.h", "win/core_winrt_util.h",
"win/current_module.h", "win/current_module.h",
"win/dark_mode_support.cc",
"win/dark_mode_support.h",
"win/default_apps_util.cc", "win/default_apps_util.cc",
"win/default_apps_util.h", "win/default_apps_util.h",
"win/embedded_i18n/language_selector.cc", "win/embedded_i18n/language_selector.cc",
@ -1269,6 +1294,14 @@ mixed_component("base") {
"message_loop/message_pump_mac.h", "message_loop/message_pump_mac.h",
"message_loop/message_pump_mac.mm", "message_loop/message_pump_mac.mm",
"native_library_mac.mm", "native_library_mac.mm",
"power_monitor/battery_level_provider.cc",
"power_monitor/battery_level_provider.h",
"power_monitor/battery_level_provider_mac.mm",
"power_monitor/iopm_power_source_sampling_event_source.cc",
"power_monitor/iopm_power_source_sampling_event_source.h",
"power_monitor/power_monitor_device_source_mac.mm",
"power_monitor/thermal_state_observer_mac.h",
"power_monitor/thermal_state_observer_mac.mm",
"process/kill_mac.cc", "process/kill_mac.cc",
"process/launch_mac.cc", "process/launch_mac.cc",
"process/memory_mac.mm", "process/memory_mac.mm",
@ -1490,6 +1523,7 @@ mixed_component("base") {
":logging_buildflags", ":logging_buildflags",
":orderfile_buildflags", ":orderfile_buildflags",
":parsing_buildflags", ":parsing_buildflags",
":power_monitor_buildflags",
":profiler_buildflags", ":profiler_buildflags",
":sanitizer_buildflags", ":sanitizer_buildflags",
":synchronization_buildflags", ":synchronization_buildflags",
@ -1967,9 +2001,6 @@ mixed_component("base") {
"files/file_enumerator_win.cc", "files/file_enumerator_win.cc",
"memory/platform_shared_memory_mapper_win.cc", "memory/platform_shared_memory_mapper_win.cc",
"memory/platform_shared_memory_region_win.cc", "memory/platform_shared_memory_region_win.cc",
"power_monitor/power_monitor_device_source_win.cc",
"power_monitor/speed_limit_observer_win.cc",
"power_monitor/speed_limit_observer_win.h",
"profiler/win32_stack_frame_unwinder.cc", "profiler/win32_stack_frame_unwinder.cc",
"profiler/win32_stack_frame_unwinder.h", "profiler/win32_stack_frame_unwinder.h",
"rand_util_win.cc", "rand_util_win.cc",
@ -2024,9 +2055,6 @@ mixed_component("base") {
"memory/platform_shared_memory_region_mac.cc", "memory/platform_shared_memory_region_mac.cc",
"message_loop/message_pump_kqueue.cc", "message_loop/message_pump_kqueue.cc",
"message_loop/message_pump_kqueue.h", "message_loop/message_pump_kqueue.h",
"power_monitor/power_monitor_device_source_mac.mm",
"power_monitor/thermal_state_observer_mac.h",
"power_monitor/thermal_state_observer_mac.mm",
"system/sys_info_mac.mm", "system/sys_info_mac.mm",
"time/time_conversion_posix.cc", "time/time_conversion_posix.cc",
"time/time_exploded_posix.cc", "time/time_exploded_posix.cc",
@ -2274,8 +2302,6 @@ mixed_component("base") {
if (enable_base_tracing) { if (enable_base_tracing) {
sources += [ sources += [
"trace_event/auto_open_close_event.h", "trace_event/auto_open_close_event.h",
"trace_event/blame_context.cc",
"trace_event/blame_context.h",
"trace_event/builtin_categories.cc", "trace_event/builtin_categories.cc",
"trace_event/builtin_categories.h", "trace_event/builtin_categories.h",
"trace_event/category_registry.cc", "trace_event/category_registry.cc",
@ -2434,6 +2460,7 @@ buildflag_header("debugging_buildflags") {
is_debug && strip_absolute_paths_from_debug_symbols && is_mac is_debug && strip_absolute_paths_from_debug_symbols && is_mac
flags = [ flags = [
"DCHECK_IS_CONFIGURABLE=$dcheck_is_configurable",
"ENABLE_LOCATION_SOURCE=$enable_location_source", "ENABLE_LOCATION_SOURCE=$enable_location_source",
"FROM_HERE_USES_LOCATION_BUILTINS=$from_here_uses_location_builtins", "FROM_HERE_USES_LOCATION_BUILTINS=$from_here_uses_location_builtins",
"ENABLE_PROFILING=$enable_profiling", "ENABLE_PROFILING=$enable_profiling",
@ -2543,6 +2570,14 @@ buildflag_header("profiler_buildflags") {
] ]
} }
buildflag_header("power_monitor_buildflags") {
header = "power_monitor_buildflags.h"
header_dir = "base/power_monitor"
_has_battery_provider_impl = is_win || is_mac
flags = [ "HAS_BATTERY_LEVEL_PROVIDER_IMPL=$_has_battery_provider_impl" ]
}
# This is the subset of files from base that should not be used with a dynamic # This is the subset of files from base that should not be used with a dynamic
# library. Note that this library cannot depend on base because base depends on # library. Note that this library cannot depend on base because base depends on
# base_static. # base_static.

View File

@ -39,8 +39,6 @@ buildflag_header("buildflags") {
# Not to be used directly - see `partition_alloc_config.h`. # Not to be used directly - see `partition_alloc_config.h`.
"USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr", "USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr",
"USE_FAKE_BINARY_EXPERIMENT=$use_fake_binary_experiment",
] ]
} }
@ -70,6 +68,9 @@ config("wrap_malloc_symbols") {
"-Wl,-wrap,realloc", "-Wl,-wrap,realloc",
"-Wl,-wrap,valloc", "-Wl,-wrap,valloc",
# Not allocating memory, but part of the API
"-Wl,-wrap,malloc_usable_size",
# <stdlib.h> functions # <stdlib.h> functions
"-Wl,-wrap,realpath", "-Wl,-wrap,realpath",

View File

@ -84,12 +84,20 @@ if (is_win && use_allocator_shim) {
_is_brp_supported = (is_win || is_android || is_linux || is_mac || _is_brp_supported = (is_win || is_android || is_linux || is_mac ||
is_chromeos) && use_allocator == "partition" is_chromeos) && use_allocator == "partition"
_is_mcp_supported = is_win && use_allocator == "partition"
declare_args() {
# We jam MTECheckedPtr off by default, but can set it to
# `_is_mcp_supported` to activate it.
use_mte_checked_ptr = false
}
declare_args() { declare_args() {
# Set use_backup_ref_ptr true to use BackupRefPtr (BRP) as the implementation # Set use_backup_ref_ptr true to use BackupRefPtr (BRP) as the implementation
# of raw_ptr<T>, and enable PartitionAlloc support for it. # of raw_ptr<T>, and enable PartitionAlloc support for it.
use_backup_ref_ptr = _is_brp_supported # We also disable BRP in the presence of MTECheckedPtr, which is almost
# never enabled.
use_mte_checked_ptr = false use_backup_ref_ptr = _is_brp_supported && !use_mte_checked_ptr
} }
assert(!(use_backup_ref_ptr && use_mte_checked_ptr), assert(!(use_backup_ref_ptr && use_mte_checked_ptr),
@ -108,11 +116,6 @@ declare_args() {
enable_backup_ref_ptr_slow_checks = false enable_backup_ref_ptr_slow_checks = false
enable_dangling_raw_ptr_checks = false enable_dangling_raw_ptr_checks = false
# Registers the binary for a fake binary A/B experiment. The binaries built
# with this flag have no behavior difference, except for setting a synthetic
# Finch.
use_fake_binary_experiment = false
# The supported platforms are supposed to match `_is_brp_supported`, but we # The supported platforms are supposed to match `_is_brp_supported`, but we
# enable the feature on Linux early because it's most widely used for security # enable the feature on Linux early because it's most widely used for security
# research # research

View File

@ -22,6 +22,7 @@ void* __real_calloc(size_t, size_t);
void* __real_realloc(void*, size_t); void* __real_realloc(void*, size_t);
void* __real_memalign(size_t, size_t); void* __real_memalign(size_t, size_t);
void __real_free(void*); void __real_free(void*);
size_t __real_malloc_usable_size(void*);
} // extern "C" } // extern "C"
namespace { namespace {
@ -57,21 +58,27 @@ void RealFree(const AllocatorDispatch*, void* address, void* context) {
__real_free(address); __real_free(address);
} }
size_t RealSizeEstimate(const AllocatorDispatch*,
void* address,
void* context) {
return __real_malloc_usable_size(address);
}
} // namespace } // namespace
const AllocatorDispatch AllocatorDispatch::default_dispatch = { const AllocatorDispatch AllocatorDispatch::default_dispatch = {
&RealMalloc, /* alloc_function */ &RealMalloc, /* alloc_function */
&RealMalloc, /* alloc_unchecked_function */ &RealMalloc, /* alloc_unchecked_function */
&RealCalloc, /* alloc_zero_initialized_function */ &RealCalloc, /* alloc_zero_initialized_function */
&RealMemalign, /* alloc_aligned_function */ &RealMemalign, /* alloc_aligned_function */
&RealRealloc, /* realloc_function */ &RealRealloc, /* realloc_function */
&RealFree, /* free_function */ &RealFree, /* free_function */
nullptr, /* get_size_estimate_function */ &RealSizeEstimate, /* get_size_estimate_function */
nullptr, /* batch_malloc_function */ nullptr, /* batch_malloc_function */
nullptr, /* batch_free_function */ nullptr, /* batch_free_function */
nullptr, /* free_definite_size_function */ nullptr, /* free_definite_size_function */
nullptr, /* aligned_malloc_function */ nullptr, /* aligned_malloc_function */
nullptr, /* aligned_realloc_function */ nullptr, /* aligned_realloc_function */
nullptr, /* aligned_free_function */ nullptr, /* aligned_free_function */
nullptr, /* next */ nullptr, /* next */
}; };

View File

@ -54,6 +54,10 @@ SHIM_ALWAYS_EXPORT void* __wrap_valloc(size_t size) {
return ShimValloc(size, nullptr); return ShimValloc(size, nullptr);
} }
SHIM_ALWAYS_EXPORT size_t __wrap_malloc_usable_size(void* address) {
return ShimGetSizeEstimate(address, nullptr);
}
const size_t kPathMaxSize = 8192; const size_t kPathMaxSize = 8192;
static_assert(kPathMaxSize >= PATH_MAX, ""); static_assert(kPathMaxSize >= PATH_MAX, "");

View File

@ -0,0 +1,24 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_CONFIGURATION_H_
#define BASE_ALLOCATOR_DISPATCHER_CONFIGURATION_H_
#include <cstddef>
namespace base::allocator::dispatcher::configuration {
// The maximum number of optional observers that may be present depending on
// command line parameters.
constexpr size_t kMaximumNumberOfOptionalObservers = 4;
// The total number of observers including mandatory and optional observers.
// Primarily the number of observers affects the performance at allocation time.
// The current value of 4 doesn't have hard evidence. Keep in mind that
// also a single observer can severely impact performance.
constexpr size_t kMaximumNumberOfObservers = 4;
} // namespace base::allocator::dispatcher::configuration
#endif // BASE_ALLOCATOR_DISPATCHER_CONFIGURATION_H_

View File

@ -6,10 +6,18 @@
#include "base/allocator/allocator_shim.h" #include "base/allocator/allocator_shim.h"
#include "base/allocator/buildflags.h" #include "base/allocator/buildflags.h"
#include "base/allocator/dispatcher/internal/dispatch_data.h"
#include "base/allocator/dispatcher/reentry_guard.h" #include "base/allocator/dispatcher/reentry_guard.h"
#include "base/allocator/partition_allocator/partition_alloc.h" #include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/check.h"
#include "base/dcheck_is_on.h"
#include "base/no_destructor.h"
#include "base/sampling_heap_profiler/poisson_allocation_sampler.h" #include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
#if DCHECK_IS_ON()
#include <atomic>
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM) #if BUILDFLAG(USE_ALLOCATOR_SHIM)
namespace base::allocator::dispatcher::allocator_shim_details { namespace base::allocator::dispatcher::allocator_shim_details {
namespace { namespace {
@ -237,3 +245,97 @@ void RemoveStandardAllocatorHooksForTesting() {
} }
} // namespace base::allocator::dispatcher } // namespace base::allocator::dispatcher
namespace base::allocator::dispatcher {
// The private implementation of Dispatcher.
struct Dispatcher::Impl {
void Initialize(const internal::DispatchData& dispatch_data) {
#if DCHECK_IS_ON()
DCHECK(!is_initialized_check_flag_.test_and_set());
#endif
dispatch_data_ = dispatch_data;
ConnectToEmitters(dispatch_data_);
}
void Reset() {
#if DCHECK_IS_ON()
DCHECK([&]() {
auto const was_set = is_initialized_check_flag_.test();
is_initialized_check_flag_.clear();
return was_set;
}());
#endif
DisconnectFromEmitters(dispatch_data_);
dispatch_data_ = {};
}
private:
// Connect the hooks to the memory subsystem. In some cases, most notably when
// we have no observers at all, the hooks will be invalid and must NOT be
// connected. This way we prevent notifications although no observers are
// present.
static void ConnectToEmitters(const internal::DispatchData& dispatch_data) {
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
if (auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch()) {
allocator::InsertAllocatorDispatch(allocator_dispatch);
}
#endif
#if BUILDFLAG(USE_PARTITION_ALLOC)
{
auto* const allocation_hook = dispatch_data.GetAllocationObserverHook();
auto* const free_hook = dispatch_data.GetFreeObserverHook();
if (allocation_hook && free_hook) {
partition_alloc::PartitionAllocHooks::SetObserverHooks(allocation_hook,
free_hook);
}
}
#endif
}
static void DisconnectFromEmitters(internal::DispatchData& dispatch_data) {
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
if (auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch()) {
allocator::RemoveAllocatorDispatchForTesting(
allocator_dispatch); // IN-TEST
}
#endif
#if BUILDFLAG(USE_PARTITION_ALLOC)
partition_alloc::PartitionAllocHooks::SetObserverHooks(nullptr, nullptr);
#endif
}
// Information on the hooks.
internal::DispatchData dispatch_data_;
#if DCHECK_IS_ON()
// Indicator if the dispatcher has been initialized before.
#if !defined(__cpp_lib_atomic_value_initialization) || \
__cpp_lib_atomic_value_initialization < 201911L
std::atomic_flag is_initialized_check_flag_ = ATOMIC_FLAG_INIT;
#else
std::atomic_flag is_initialized_check_flag_;
#endif
#endif
};
Dispatcher::Dispatcher() : impl_(std::make_unique<Impl>()) {}
Dispatcher::~Dispatcher() = default;
Dispatcher& Dispatcher::GetInstance() {
static base::NoDestructor<Dispatcher> instance;
return *instance;
}
void Dispatcher::Initialize(const internal::DispatchData& dispatch_data) {
impl_->Initialize(dispatch_data);
}
void Dispatcher::ResetForTesting() {
impl_->Reset();
}
} // namespace base::allocator::dispatcher

View File

@ -5,13 +5,74 @@
#ifndef BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_ #ifndef BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_
#define BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_ #define BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_
#include "base/allocator/dispatcher/internal/dispatcher_internal.h"
#include "base/base_export.h" #include "base/base_export.h"
#include <memory>
namespace base::allocator::dispatcher { namespace base::allocator::dispatcher {
void BASE_EXPORT InstallStandardAllocatorHooks(); void BASE_EXPORT InstallStandardAllocatorHooks();
void BASE_EXPORT RemoveStandardAllocatorHooksForTesting(); void BASE_EXPORT RemoveStandardAllocatorHooksForTesting();
namespace internal {
struct DispatchData;
}
// Dispatcher serves as the top level instance for managing the dispatch
// mechanism. The class instance manages connections to the various memory
// subsystems such as PartitionAlloc. To keep the public interface as lean as
// possible it uses a pimpl pattern.
class BASE_EXPORT Dispatcher {
public:
static Dispatcher& GetInstance();
Dispatcher();
// Initialize the dispatch mechanism with the given tuple of observers. The
// observers must be valid (it is only DCHECKed internally at initialization,
// but not verified further)
// If Initialize is called multiple times, the first one wins. All later
// invocations are silently ignored. Initialization is protected from
// concurrent invocations. In case of concurrent accesses, the first one to
// get the lock wins.
// The dispatcher invokes following functions on the observers:
// void OnAllocation(void* address,
// size_t size,
// AllocationSubsystem sub_system,
// const char* type_name);
// void OnFree(void* address);
//
// Note: The dispatcher mechanism does NOT bring systematic protection against
// recursive invocations. That is, observers which allocate memory on the
// heap, i.e. through dynamically allocated containers or by using the
// CHECK-macro, are responsible to break these recursions!
template <typename... ObserverTypes>
void Initialize(const std::tuple<ObserverTypes...>& observers) {
// Get the hooks for running these observers and pass them to further
// initialization
Initialize(internal::GetNotificationHooks(observers));
}
// The following functions provide an interface to setup and tear down the
// dispatcher when testing. This must NOT be used from production code since
// the hooks cannot be removed reliably under all circumstances.
template <typename ObserverType>
void InitializeForTesting(ObserverType* observer) {
Initialize(std::make_tuple(observer));
}
void ResetForTesting();
private:
// structure and pointer to the private implementation.
struct Impl;
std::unique_ptr<Impl> const impl_;
~Dispatcher();
void Initialize(const internal::DispatchData& dispatch_data);
};
} // namespace base::allocator::dispatcher } // namespace base::allocator::dispatcher
#endif // BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_ #endif // BASE_ALLOCATOR_DISPATCHER_DISPATCHER_H_

View File

@ -0,0 +1,206 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_
#define BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_
#include "base/allocator/dispatcher/configuration.h"
#include "base/allocator/dispatcher/dispatcher.h"
#include "base/allocator/dispatcher/internal/tools.h"
#include <tuple>
#include <utility>
namespace base::allocator::dispatcher {
namespace internal {
// Filter the passed observers and perform initialization of the passed
// dispatcher.
template <size_t CurrentIndex,
typename DispatcherType,
typename CheckObserverPredicate,
typename VerifiedObservers,
typename UnverifiedObservers,
size_t... IndicesToSelect>
inline void DoInitialize(DispatcherType& dispatcher,
CheckObserverPredicate check_observer,
const VerifiedObservers& verified_observers,
const UnverifiedObservers& unverified_observers,
std::index_sequence<IndicesToSelect...> indices) {
if constexpr (CurrentIndex < std::tuple_size<UnverifiedObservers>::value) {
// We still have some items left to handle.
if (check_observer(std::get<CurrentIndex>(unverified_observers))) {
// The current observer is valid. Hence, append the index of the current
// item to the set of indices and head on to the next item.
DoInitialize<CurrentIndex + 1>(
dispatcher, check_observer, verified_observers, unverified_observers,
std::index_sequence<IndicesToSelect..., CurrentIndex>{});
} else {
// The current observer is not valid. Hence, head on to the next item with
// an unaltered list of indices.
DoInitialize<CurrentIndex + 1>(dispatcher, check_observer,
verified_observers, unverified_observers,
indices);
}
} else if constexpr (CurrentIndex ==
std::tuple_size<UnverifiedObservers>::value) {
// So we have met the end of the tuple of observers to verify.
// Hence, we extract the additional valid observers, append to the tuple of
// already verified observers and hand over to the dispatcher.
auto observers = std::tuple_cat(
verified_observers,
std::make_tuple(std::get<IndicesToSelect>(unverified_observers)...));
// Do a final check that neither the maximum total number of observers nor
// the maximum number of optional observers is exceeded.
static_assert(std::tuple_size<decltype(observers)>::value <=
configuration::kMaximumNumberOfObservers);
static_assert(sizeof...(IndicesToSelect) <=
configuration::kMaximumNumberOfOptionalObservers);
dispatcher.Initialize(std::move(observers));
}
}
} // namespace internal
// The result of concatenating two tuple-types.
template <typename... tuples>
using TupleCat = decltype(std::tuple_cat(std::declval<tuples>()...));
// Initializer collects mandatory and optional observers and initializes the
// passed Dispatcher with only the enabled observers.
//
// In some situations, presence of observers depends on runtime. i.e. command
// line parameters or CPU features. With 3 optional observers we already have 8
// different combinations. Initializer takes the job of dealing with all
// combinations from the user. It allows users to pass all observers (including
// nullptr for disabled optional observers) and initializes the Dispatcher with
// only the enabled observers.
//
// Since this process results in a combinatoric explosion, Initializer
// distinguishes between optional and mandatory observers. Mandatory observers
// are not included in the filtering process and must always be enabled (not
// nullptr).
//
// To allow the Initializer to track the number and exact type of observers, it
// is implemented as a templated class which holds information on the types in
// the std::tuples passed as template parameters. Therefore, whenever any type
// observer it set, the initializer changes its type to reflect this.
template <typename MandatoryObservers = std::tuple<>,
typename OptionalObservers = std::tuple<>>
struct BASE_EXPORT Initializer {
Initializer() = default;
Initializer(MandatoryObservers mandatory_observers,
OptionalObservers optional_observers)
: mandatory_observers_(std::move(mandatory_observers)),
optional_observers_(std::move(optional_observers)) {}
// Set the mandatory observers. The number of observers that can be set is
// limited by configuration::maximum_number_of_observers.
template <typename... NewMandatoryObservers,
std::enable_if_t<
internal::LessEqual((sizeof...(NewMandatoryObservers) +
std::tuple_size<OptionalObservers>::value),
configuration::kMaximumNumberOfObservers),
bool> = true>
Initializer<std::tuple<NewMandatoryObservers*...>, OptionalObservers>
SetMandatoryObservers(NewMandatoryObservers*... mandatory_observers) const {
return {std::make_tuple(mandatory_observers...), GetOptionalObservers()};
}
// Add mandatory observers. The number of observers that can be added is
// limited by the current number of observers, see
// configuration::maximum_number_of_observers.
template <typename... AdditionalMandatoryObservers,
std::enable_if_t<internal::LessEqual(
std::tuple_size<MandatoryObservers>::value +
sizeof...(AdditionalMandatoryObservers) +
std::tuple_size<OptionalObservers>::value,
configuration::kMaximumNumberOfObservers),
bool> = true>
Initializer<TupleCat<MandatoryObservers,
std::tuple<AdditionalMandatoryObservers*...>>,
OptionalObservers>
AddMandatoryObservers(
AdditionalMandatoryObservers*... additional_mandatory_observers) const {
return {std::tuple_cat(GetMandatoryObservers(),
std::make_tuple(additional_mandatory_observers...)),
GetOptionalObservers()};
}
// Set the optional observers. The number of observers that can be set is
// limited by configuration::maximum_number_of_optional_observers as well as
// configuration::maximum_number_of_observers.
template <
typename... NewOptionalObservers,
std::enable_if_t<
internal::LessEqual(
sizeof...(NewOptionalObservers),
configuration::kMaximumNumberOfOptionalObservers) &&
internal::LessEqual((sizeof...(NewOptionalObservers) +
std::tuple_size<MandatoryObservers>::value),
configuration::kMaximumNumberOfObservers),
bool> = true>
Initializer<MandatoryObservers, std::tuple<NewOptionalObservers*...>>
SetOptionalObservers(NewOptionalObservers*... optional_observers) const {
return {GetMandatoryObservers(), std::make_tuple(optional_observers...)};
}
// Add optional observers. The number of observers that can be added is
// limited by the current number of optional observers,
// configuration::maximum_number_of_optional_observers as well as
// configuration::maximum_number_of_observers.
template <
typename... AdditionalOptionalObservers,
std::enable_if_t<
internal::LessEqual(
std::tuple_size<OptionalObservers>::value +
sizeof...(AdditionalOptionalObservers),
configuration::kMaximumNumberOfOptionalObservers) &&
internal::LessEqual((std::tuple_size<OptionalObservers>::value +
sizeof...(AdditionalOptionalObservers) +
std::tuple_size<MandatoryObservers>::value),
configuration::kMaximumNumberOfObservers),
bool> = true>
Initializer<
MandatoryObservers,
TupleCat<OptionalObservers, std::tuple<AdditionalOptionalObservers*...>>>
AddOptionalObservers(
AdditionalOptionalObservers*... additional_optional_observers) const {
return {GetMandatoryObservers(),
std::tuple_cat(GetOptionalObservers(),
std::make_tuple(additional_optional_observers...))};
}
// Perform the actual initialization on the passed dispatcher.
// The dispatcher is passed as a template only to provide better testability.
template <typename DispatcherType>
void DoInitialize(DispatcherType& dispatcher) const {
internal::DoInitialize<0>(dispatcher, internal::IsValidObserver{},
GetMandatoryObservers(), GetOptionalObservers(),
{});
}
const MandatoryObservers& GetMandatoryObservers() const {
return mandatory_observers_;
}
const OptionalObservers& GetOptionalObservers() const {
return optional_observers_;
}
private:
MandatoryObservers mandatory_observers_;
OptionalObservers optional_observers_;
};
// Convenience function for creating an empty Initializer.
inline Initializer<> CreateInitializer() {
return {};
}
} // namespace base::allocator::dispatcher
#endif // BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_

View File

@ -0,0 +1,41 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/allocator/dispatcher/internal/dispatch_data.h"
namespace base::allocator::dispatcher::internal {
#if BUILDFLAG(USE_PARTITION_ALLOC)
DispatchData& DispatchData::SetAllocationObserverHooks(
AllocationObserverHook* allocation_observer_hook,
FreeObserverHook* free_observer_hook) {
allocation_observer_hook_ = allocation_observer_hook;
free_observer_hook_ = free_observer_hook;
return *this;
}
DispatchData::AllocationObserverHook* DispatchData::GetAllocationObserverHook()
const {
return allocation_observer_hook_;
}
DispatchData::FreeObserverHook* DispatchData::GetFreeObserverHook() const {
return free_observer_hook_;
}
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
DispatchData& DispatchData::SetAllocatorDispatch(
AllocatorDispatch* allocator_dispatch) {
allocator_dispatch_ = allocator_dispatch;
return *this;
}
AllocatorDispatch* DispatchData::GetAllocatorDispatch() const {
return allocator_dispatch_;
}
#endif
} // namespace base::allocator::dispatcher::internal

View File

@ -0,0 +1,54 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCH_DATA_H_
#define BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCH_DATA_H_
#include "base/allocator/buildflags.h"
#include "base/base_export.h"
#include "build/build_config.h"
#if BUILDFLAG(USE_PARTITION_ALLOC)
#include "base/allocator/partition_allocator/partition_alloc.h"
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
#include "base/allocator/allocator_shim.h"
#endif
namespace base::allocator::dispatcher::internal {
// A simple utility class to pass all the information required to properly hook
// into the memory allocation subsystems from DispatcherImpl to the Dispatcher.
struct BASE_EXPORT DispatchData {
#if BUILDFLAG(USE_PARTITION_ALLOC)
using AllocationObserverHook =
partition_alloc::PartitionAllocHooks::AllocationObserverHook;
using FreeObserverHook =
partition_alloc::PartitionAllocHooks::FreeObserverHook;
DispatchData& SetAllocationObserverHooks(AllocationObserverHook*,
FreeObserverHook*);
AllocationObserverHook* GetAllocationObserverHook() const;
FreeObserverHook* GetFreeObserverHook() const;
private:
AllocationObserverHook* allocation_observer_hook_ = nullptr;
FreeObserverHook* free_observer_hook_ = nullptr;
public:
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
DispatchData& SetAllocatorDispatch(AllocatorDispatch* allocator_dispatch);
AllocatorDispatch* GetAllocatorDispatch() const;
private:
AllocatorDispatch* allocator_dispatch_ = nullptr;
#endif
};
} // namespace base::allocator::dispatcher::internal
#endif

View File

@ -0,0 +1,351 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_INTERNAL_H_
#define BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_INTERNAL_H_
#include "base/allocator/buildflags.h"
#include "base/allocator/dispatcher/configuration.h"
#include "base/allocator/dispatcher/internal/dispatch_data.h"
#include "base/allocator/dispatcher/internal/tools.h"
#include "base/allocator/dispatcher/reentry_guard.h"
#include "base/allocator/dispatcher/subsystem.h"
#include "base/compiler_specific.h"
#include "build/build_config.h"
#if BUILDFLAG(USE_PARTITION_ALLOC)
#include "base/allocator/partition_allocator/partition_alloc.h"
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
#include "base/allocator/allocator_shim.h"
#endif
#include <tuple>
namespace base::allocator::dispatcher::internal {
template <typename CheckObserverPredicate,
typename... ObserverTypes,
size_t... Indices>
void inline PerformObserverCheck(const std::tuple<ObserverTypes...>& observers,
std::index_sequence<Indices...>,
CheckObserverPredicate check_observer) {
((DCHECK(check_observer(std::get<Indices>(observers)))), ...);
}
template <typename... ObserverTypes, size_t... Indices>
ALWAYS_INLINE void PerformAllocationNotification(
const std::tuple<ObserverTypes...>& observers,
std::index_sequence<Indices...>,
void* address,
size_t size,
AllocationSubsystem subSystem,
const char* type_name) {
((std::get<Indices>(observers)->OnAllocation(address, size, subSystem,
type_name)),
...);
}
template <typename... ObserverTypes, size_t... Indices>
ALWAYS_INLINE void PerformFreeNotification(
const std::tuple<ObserverTypes...>& observers,
std::index_sequence<Indices...>,
void* address) {
((std::get<Indices>(observers)->OnFree(address)), ...);
}
// DispatcherImpl provides hooks into the various memory subsystems. These hooks
// are responsible for dispatching any notification to the observers.
// In order to provide as many information on the exact type of the observer and
// prevent any conditional jumps in the hot allocation path, observers are
// stored in a std::tuple. DispatcherImpl performs a CHECK at initialization
// time to ensure they are valid.
template <typename... ObserverTypes>
struct DispatcherImpl {
using AllObservers = std::index_sequence_for<ObserverTypes...>;
template <std::enable_if_t<
internal::LessEqual(sizeof...(ObserverTypes),
configuration::kMaximumNumberOfObservers),
bool> = true>
static DispatchData GetNotificationHooks(
std::tuple<ObserverTypes*...> observers) {
s_observers = std::move(observers);
PerformObserverCheck(s_observers, AllObservers{}, IsValidObserver{});
return CreateDispatchData();
}
private:
static DispatchData CreateDispatchData() {
return DispatchData()
#if BUILDFLAG(USE_PARTITION_ALLOC)
.SetAllocationObserverHooks(&PartitionAllocatorAllocationHook,
&PartitionAllocatorFreeHook)
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
.SetAllocatorDispatch(&allocator_dispatch_)
#endif
;
}
#if BUILDFLAG(USE_PARTITION_ALLOC)
static void PartitionAllocatorAllocationHook(void* address,
size_t size,
const char* type_name) {
DoNotifyAllocation(address, size, AllocationSubsystem::kPartitionAllocator,
type_name);
}
static void PartitionAllocatorFreeHook(void* address) {
DoNotifyFree(address);
}
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
static void* AllocFn(const AllocatorDispatch* self,
size_t size,
void* context) {
ReentryGuard guard;
void* const address = self->next->alloc_function(self->next, size, context);
if (LIKELY(guard)) {
DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim);
}
return address;
}
static void* AllocUncheckedFn(const AllocatorDispatch* self,
size_t size,
void* context) {
ReentryGuard guard;
void* const address =
self->next->alloc_unchecked_function(self->next, size, context);
if (LIKELY(guard)) {
DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim);
}
return address;
}
static void* AllocZeroInitializedFn(const AllocatorDispatch* self,
size_t n,
size_t size,
void* context) {
ReentryGuard guard;
void* const address = self->next->alloc_zero_initialized_function(
self->next, n, size, context);
if (LIKELY(guard)) {
DoNotifyAllocation(address, n * size,
AllocationSubsystem::kAllocatorShim);
}
return address;
}
static void* AllocAlignedFn(const AllocatorDispatch* self,
size_t alignment,
size_t size,
void* context) {
ReentryGuard guard;
void* const address = self->next->alloc_aligned_function(
self->next, alignment, size, context);
if (LIKELY(guard)) {
DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim);
}
return address;
}
static void* ReallocFn(const AllocatorDispatch* self,
void* address,
size_t size,
void* context) {
ReentryGuard guard;
// Note: size == 0 actually performs free.
// Note: ReentryGuard prevents from recursions introduced by malloc and
// initialization of thread local storage which happen in the allocation
// path only (please see docs of ReentryGuard for full details). Therefore,
// the DoNotifyFree doesn't need to be guarded. Instead, making it unguarded
// also ensures proper notification.
DoNotifyFree(address);
void* const reallocated_address =
self->next->realloc_function(self->next, address, size, context);
if (LIKELY(guard)) {
DoNotifyAllocation(reallocated_address, size,
AllocationSubsystem::kAllocatorShim);
}
return reallocated_address;
}
static void FreeFn(const AllocatorDispatch* self,
void* address,
void* context) {
// Note: The RecordFree should be called before free_function (here and in
// other places). That is because observers need to handle the allocation
// being freed before calling free_function, as once the latter is executed
// the address becomes available and can be allocated by another thread.
// That would be racy otherwise.
// Note: The code doesn't need to protect from recursions using
// ReentryGuard, see ReallocFn for details.
DoNotifyFree(address);
self->next->free_function(self->next, address, context);
}
static size_t GetSizeEstimateFn(const AllocatorDispatch* self,
void* address,
void* context) {
return self->next->get_size_estimate_function(self->next, address, context);
}
static unsigned BatchMallocFn(const AllocatorDispatch* self,
size_t size,
void** results,
unsigned num_requested,
void* context) {
ReentryGuard guard;
unsigned const num_allocated = self->next->batch_malloc_function(
self->next, size, results, num_requested, context);
if (LIKELY(guard)) {
for (unsigned i = 0; i < num_allocated; ++i) {
DoNotifyAllocation(results[i], size,
AllocationSubsystem::kAllocatorShim);
}
}
return num_allocated;
}
static void BatchFreeFn(const AllocatorDispatch* self,
void** to_be_freed,
unsigned num_to_be_freed,
void* context) {
// Note: The code doesn't need to protect from recursions using
// ReentryGuard, see ReallocFn for details.
for (unsigned i = 0; i < num_to_be_freed; ++i) {
DoNotifyFree(to_be_freed[i]);
}
self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed,
context);
}
static void FreeDefiniteSizeFn(const AllocatorDispatch* self,
void* address,
size_t size,
void* context) {
// Note: The code doesn't need to protect from recursions using
// ReentryGuard, see ReallocFn for details.
DoNotifyFree(address);
self->next->free_definite_size_function(self->next, address, size, context);
}
static void* AlignedMallocFn(const AllocatorDispatch* self,
size_t size,
size_t alignment,
void* context) {
ReentryGuard guard;
void* const address = self->next->aligned_malloc_function(
self->next, size, alignment, context);
if (LIKELY(guard)) {
DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim);
}
return address;
}
static void* AlignedReallocFn(const AllocatorDispatch* self,
void* address,
size_t size,
size_t alignment,
void* context) {
ReentryGuard guard;
// Note: size == 0 actually performs free.
// Note: DoNotifyFree doesn't need to protect from recursions using
// ReentryGuard, see ReallocFn for details.
// Instead, making it unguarded also ensures proper notification of the free
// portion.
DoNotifyFree(address);
address = self->next->aligned_realloc_function(self->next, address, size,
alignment, context);
if (LIKELY(guard)) {
DoNotifyAllocation(address, size, AllocationSubsystem::kAllocatorShim);
}
return address;
}
static void AlignedFreeFn(const AllocatorDispatch* self,
void* address,
void* context) {
// Note: The code doesn't need to protect from recursions using
// ReentryGuard, see ReallocFn for details.
DoNotifyFree(address);
self->next->aligned_free_function(self->next, address, context);
}
static AllocatorDispatch allocator_dispatch_;
#endif
static ALWAYS_INLINE void DoNotifyAllocation(
void* address,
size_t size,
AllocationSubsystem subSystem,
const char* type_name = nullptr) {
PerformAllocationNotification(s_observers, AllObservers{}, address, size,
subSystem, type_name);
}
static ALWAYS_INLINE void DoNotifyFree(void* address) {
PerformFreeNotification(s_observers, AllObservers{}, address);
}
static std::tuple<ObserverTypes*...> s_observers;
};
template <typename... ObserverTypes>
std::tuple<ObserverTypes*...> DispatcherImpl<ObserverTypes...>::s_observers;
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
template <typename... ObserverTypes>
AllocatorDispatch DispatcherImpl<ObserverTypes...>::allocator_dispatch_ = {
&AllocFn,
&AllocUncheckedFn,
&AllocZeroInitializedFn,
&AllocAlignedFn,
&ReallocFn,
&FreeFn,
&GetSizeEstimateFn,
&BatchMallocFn,
&BatchFreeFn,
&FreeDefiniteSizeFn,
&AlignedMallocFn,
&AlignedReallocFn,
&AlignedFreeFn,
nullptr};
#endif
// Specialization of DispatcherImpl in case we have no observers to notify. In
// this special case we return a set of null pointers as the Dispatcher must not
// install any hooks at all.
template <>
struct DispatcherImpl<> {
static DispatchData GetNotificationHooks(std::tuple<> /*observers*/) {
return DispatchData()
#if BUILDFLAG(USE_PARTITION_ALLOC)
.SetAllocationObserverHooks(nullptr, nullptr)
#endif
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
.SetAllocatorDispatch(nullptr)
#endif
;
}
};
// A little utility function that helps using DispatcherImpl by providing
// automated type deduction for templates.
template <typename... ObserverTypes>
inline DispatchData GetNotificationHooks(
std::tuple<ObserverTypes*...> observers) {
return DispatcherImpl<ObserverTypes...>::GetNotificationHooks(
std::move(observers));
}
} // namespace base::allocator::dispatcher::internal
#endif // BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_INTERNAL_H_

View File

@ -0,0 +1,29 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_INTERNAL_TOOLS_H_
#define BASE_ALLOCATOR_DISPATCHER_INTERNAL_TOOLS_H_
#include <cstddef>
namespace base::allocator::dispatcher::internal {
constexpr bool LessEqual(size_t lhs, size_t rhs) {
return lhs <= rhs;
}
constexpr bool Equal(size_t lhs, size_t rhs) {
return lhs == rhs;
}
struct IsValidObserver {
template <typename T>
constexpr bool operator()(T const* ptr) const noexcept {
return ptr != nullptr;
}
};
} // namespace base::allocator::dispatcher::internal
#endif // BASE_ALLOCATOR_DISPATCHER_INTERNAL_DISPATCHER_H_

View File

@ -9,12 +9,26 @@
#include "build/build_config.h" #include "build/build_config.h"
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
#include <pthread.h> #include <pthread.h>
#endif
namespace base::allocator::dispatcher { namespace base::allocator::dispatcher {
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
pthread_key_t ReentryGuard::entered_key_ = 0; pthread_key_t ReentryGuard::entered_key_ = 0;
} // namespace base::allocator::dispatcher void ReentryGuard::InitTLSSlot() {
if (entered_key_ == 0) {
int error = pthread_key_create(&entered_key_, nullptr);
CHECK(!error);
}
DCHECK(entered_key_ != 0);
}
#else
void ReentryGuard::InitTLSSlot() {}
#endif #endif
} // namespace base::allocator::dispatcher

View File

@ -25,7 +25,7 @@ namespace base::allocator::dispatcher {
// Besides that the implementations of thread_local on macOS and Android // Besides that the implementations of thread_local on macOS and Android
// seem to allocate memory lazily on the first access to thread_local variables. // seem to allocate memory lazily on the first access to thread_local variables.
// Make use of pthread TLS instead of C++ thread_local there. // Make use of pthread TLS instead of C++ thread_local there.
struct ReentryGuard { struct BASE_EXPORT ReentryGuard {
ReentryGuard() : allowed_(!pthread_getspecific(entered_key_)) { ReentryGuard() : allowed_(!pthread_getspecific(entered_key_)) {
pthread_setspecific(entered_key_, reinterpret_cast<void*>(true)); pthread_setspecific(entered_key_, reinterpret_cast<void*>(true));
} }
@ -41,10 +41,7 @@ struct ReentryGuard {
// order to acquire a low TLS slot number because glibc TLS implementation // order to acquire a low TLS slot number because glibc TLS implementation
// will require a malloc call to allocate storage for a higher slot number // will require a malloc call to allocate storage for a higher slot number
// (>= PTHREAD_KEY_2NDLEVEL_SIZE == 32). c.f. heap_profiling::InitTLSSlot. // (>= PTHREAD_KEY_2NDLEVEL_SIZE == 32). c.f. heap_profiling::InitTLSSlot.
static void Init() { static void InitTLSSlot();
int error = pthread_key_create(&entered_key_, nullptr);
CHECK(!error);
}
private: private:
static pthread_key_t entered_key_; static pthread_key_t entered_key_;
@ -58,7 +55,7 @@ struct ReentryGuard {
struct [[maybe_unused]] BASE_EXPORT ReentryGuard { struct [[maybe_unused]] BASE_EXPORT ReentryGuard {
constexpr explicit operator bool() const noexcept { return true; } constexpr explicit operator bool() const noexcept { return true; }
static void Init() {} static void InitTLSSlot();
}; };
#endif #endif

View File

@ -0,0 +1,21 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_SUBSYSTEM_H_
#define BASE_ALLOCATOR_DISPATCHER_SUBSYSTEM_H_
namespace base::allocator::dispatcher {
// Identifiers for the memory subsystem handling the allocation. Some observers
// require more detailed information on who is performing the allocation, i.e.
// SamplingHeapProfiler.
enum class AllocationSubsystem {
// Allocation is handled by PartitionAllocator.
kPartitionAllocator = 1,
// Allocation is handled by AllocatorShims.
kAllocatorShim = 2
};
} // namespace base::allocator::dispatcher
#endif // BASE_ALLOCATOR_DISPATCHER_SUBSYSTEM_H_

View File

@ -0,0 +1,27 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_TESTING_DISPATCHER_TEST_H_
#define BASE_ALLOCATOR_DISPATCHER_TESTING_DISPATCHER_TEST_H_
#include "testing/gtest/include/gtest/gtest.h"
namespace base::allocator::dispatcher::testing {
// DispatcherTest provides some common initialization which most of the
// unittests of the dispatcher require. DispatcherTest should not be used
// directly. Instead, derive your test fixture from it.
struct DispatcherTest : public ::testing::Test {
// Perform some commonly required initialization, at them moment
// - Initialize the TLS slot for the ReentryGuard
DispatcherTest();
protected:
// Protected d'tor only to prevent direct usage of this class.
~DispatcherTest() override;
};
} // namespace base::allocator::dispatcher::testing
#endif // BASE_ALLOCATOR_DISPATCHER_TESTING_DISPATCHER_TEST_H_

View File

@ -0,0 +1,32 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_TESTING_OBSERVER_MOCK_H_
#define BASE_ALLOCATOR_DISPATCHER_TESTING_OBSERVER_MOCK_H_
#include "base/allocator/dispatcher/subsystem.h"
#include "testing/gmock/include/gmock/gmock.h"
#include <cstddef>
namespace base::allocator::dispatcher::testing {
// ObserverMock is a small mock class based on GoogleMock.
// It complies to the interface enforced by the dispatcher. The template
// parameter serves only to create distinct types of observers if required.
template <typename T = void>
struct ObserverMock {
MOCK_METHOD(void,
OnAllocation,
(void* address,
size_t size,
AllocationSubsystem sub_system,
const char* type_name),
());
MOCK_METHOD(void, OnFree, (void* address), ());
};
} // namespace base::allocator::dispatcher::testing
#endif // BASE_ALLOCATOR_DISPATCHER_TESTING_OBSERVER_MOCK_H_

View File

@ -0,0 +1,50 @@
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_DISPATCHER_TESTING_TOOLS_H_
#define BASE_ALLOCATOR_DISPATCHER_TESTING_TOOLS_H_
#include <array>
#include <tuple>
#include <utility>
namespace base::allocator::dispatcher::testing {
namespace internal {
template <size_t Size, typename Type, typename... AppendedTypes>
struct DefineTupleFromSingleType {
using type = typename DefineTupleFromSingleType<Size - 1,
Type,
AppendedTypes...,
Type>::type;
};
template <typename Type, typename... AppendedTypes>
struct DefineTupleFromSingleType<0, Type, AppendedTypes...> {
using type = std::tuple<AppendedTypes...>;
};
} // namespace internal
template <size_t Size, typename Type>
struct DefineTupleFromSingleType {
using type = typename internal::DefineTupleFromSingleType<Size, Type>::type;
};
template <typename Type, size_t Size, size_t... Indices>
typename internal::DefineTupleFromSingleType<Size, Type*>::type
CreateTupleOfPointers(std::array<Type, Size>& items,
std::index_sequence<Indices...>) {
return std::make_tuple((&items[Indices])...);
}
template <typename Type, size_t Size>
typename internal::DefineTupleFromSingleType<Size, Type*>::type
CreateTupleOfPointers(std::array<Type, Size>& items) {
return CreateTupleOfPointers(items, std::make_index_sequence<Size>{});
}
} // namespace base::allocator::dispatcher::testing
#endif

View File

@ -9,12 +9,10 @@
#include "base/allocator/partition_allocator/partition_alloc_config.h" #include "base/allocator/partition_allocator/partition_alloc_config.h"
#include "base/base_export.h" #include "base/base_export.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
namespace base { namespace base {
struct Feature;
namespace features { namespace features {
// See /docs/dangling_ptr.md // See /docs/dangling_ptr.md

View File

@ -359,14 +359,6 @@ std::map<std::string, std::string> ProposeSyntheticFinchTrials() {
trials.emplace("PCScan_Effective_Fallback", pcscan_group_name_fallback); trials.emplace("PCScan_Effective_Fallback", pcscan_group_name_fallback);
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
trials.emplace("FakeBinaryExperiment",
#if BUILDFLAG(USE_FAKE_BINARY_EXPERIMENT)
"Enabled"
#else
"Disabled"
#endif
);
return trials; return trials;
} }

View File

@ -44,7 +44,11 @@ if (is_fuchsia) {
if (make_partition_alloc_standalone) { if (make_partition_alloc_standalone) {
partition_alloc_target_type = "component" partition_alloc_target_type = "component"
} else { } else {
partition_alloc_target_type = "source_set" if (is_component_build) {
partition_alloc_target_type = "source_set"
} else {
partition_alloc_target_type = "static_library"
}
} }
target(partition_alloc_target_type, "partition_alloc") { target(partition_alloc_target_type, "partition_alloc") {
@ -127,6 +131,7 @@ target(partition_alloc_target_type, "partition_alloc") {
"partition_alloc_base/time/time.h", "partition_alloc_base/time/time.h",
"partition_alloc_base/time/time_override.cc", "partition_alloc_base/time/time_override.cc",
"partition_alloc_base/time/time_override.h", "partition_alloc_base/time/time_override.h",
"partition_alloc_base/types/strong_alias.h",
"partition_alloc_base/win/windows_types.h", "partition_alloc_base/win/windows_types.h",
"partition_alloc_check.h", "partition_alloc_check.h",
"partition_alloc_config.h", "partition_alloc_config.h",
@ -153,6 +158,7 @@ target(partition_alloc_target_type, "partition_alloc") {
"partition_stats.h", "partition_stats.h",
"partition_tag.h", "partition_tag.h",
"partition_tag_bitmap.h", "partition_tag_bitmap.h",
"partition_tag_types.h",
"partition_tls.h", "partition_tls.h",
"random.cc", "random.cc",
"random.h", "random.h",
@ -277,17 +283,13 @@ target(partition_alloc_target_type, "partition_alloc") {
":debugging_buildflags", ":debugging_buildflags",
":logging_buildflags", ":logging_buildflags",
":partition_alloc_buildflags", ":partition_alloc_buildflags",
"//build:branding_buildflags",
"//build/config/compiler:compiler_buildflags",
] ]
# TODO(https://crbug.com/1151236): Remove this dependency on Abseil once PA
# no longer includes any headers directly from base/.
deps = [ "//third_party/abseil-cpp:absl" ]
configs += [ configs += [
":partition_alloc_implementation", ":partition_alloc_implementation",
":memory_tagging", ":memory_tagging",
] ]
deps = []
public_configs = [] public_configs = []
if (is_android) { if (is_android) {
# tagging.cc requires __arm_mte_set_* functions. # tagging.cc requires __arm_mte_set_* functions.
@ -345,7 +347,7 @@ buildflag_header("partition_alloc_buildflags") {
_record_alloc_info = false _record_alloc_info = false
# TODO(crbug.com/1151236): Need to refactor the following buildflags. # TODO(crbug.com/1151236): Need to refactor the following buildflags.
# The buildflags (expect RECORD_ALLOC_INFO) are used by both chrome and # The buildflags (except RECORD_ALLOC_INFO) are used by both chrome and
# partition alloc. For partition alloc, # partition alloc. For partition alloc,
# gen/base/allocator/partition_allocator/partition_alloc_buildflags.h # gen/base/allocator/partition_allocator/partition_alloc_buildflags.h
# defines and partition alloc includes the header file. For chrome, # defines and partition alloc includes the header file. For chrome,
@ -361,6 +363,7 @@ buildflag_header("partition_alloc_buildflags") {
"USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr", "USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr",
"RECORD_ALLOC_INFO=$_record_alloc_info", "RECORD_ALLOC_INFO=$_record_alloc_info",
"USE_FREESLOT_BITMAP=$use_freeslot_bitmap",
] ]
} }
@ -396,6 +399,7 @@ buildflag_header("debugging_buildflags") {
flags = [ flags = [
"PA_DCHECK_IS_ON=$_dcheck_is_on", "PA_DCHECK_IS_ON=$_dcheck_is_on",
"PA_EXPENSIVE_DCHECKS_ARE_ON=$enable_expensive_dchecks", "PA_EXPENSIVE_DCHECKS_ARE_ON=$enable_expensive_dchecks",
"PA_DCHECK_IS_CONFIGURABLE=$dcheck_is_configurable",
] ]
} }
@ -408,8 +412,6 @@ group("buildflags") {
":partition_alloc_buildflags", ":partition_alloc_buildflags",
] ]
} }
# TODO(crbug.com/1151236): After making partition_alloc a standalone library, # TODO(crbug.com/1151236): After making partition_alloc a standalone library,
# move test code here. i.e. test("partition_alloc_tests") { ... } and # move test code here. i.e. test("partition_alloc_tests") { ... } and
# test("partition_alloc_perftests"). # test("partition_alloc_perftests").

View File

@ -4,16 +4,19 @@ This document describes PartitionAlloc at a high level, with some architectural
details. For implementation details, see the comments in details. For implementation details, see the comments in
`partition_alloc_constants.h`. `partition_alloc_constants.h`.
## Quick Links
* [Glossary](./glossary.md): Definitions of terms commonly used in
PartitionAlloc. The present document largely avoids defining terms.
* [Build Config](./build_config.md): Pertinent GN args, buildflags, and
macros.
## Overview ## Overview
PartitionAlloc is a memory allocator optimized for space efficiency, PartitionAlloc is a memory allocator optimized for space efficiency,
allocation latency, and security. allocation latency, and security.
*** note
This document largely avoids defining terms; consult the
[glossary](./glossary.md) for a complete reference.
***
### Performance ### Performance
PartitionAlloc is designed to be extremely fast in its fast paths. The fast PartitionAlloc is designed to be extremely fast in its fast paths. The fast

View File

@ -9,6 +9,12 @@ each term depends mainly upon previously defined ones.
* **Partition**: A heap that is separated and protected both from other * **Partition**: A heap that is separated and protected both from other
partitions and from non-PartitionAlloc memory. Each partition holds partitions and from non-PartitionAlloc memory. Each partition holds
multiple buckets. multiple buckets.
*** promo
**NOTE**: In code (and comments), "partition," "root," and even
"allocator" are all conceptually the same thing.
***
* **Bucket**: A collection of regions in a partition that contains * **Bucket**: A collection of regions in a partition that contains
similar-sized objects. For example, one bucket may hold objects of similar-sized objects. For example, one bucket may hold objects of
size (224,&nbsp;256], another (256,&nbsp;320], etc. Bucket size size (224,&nbsp;256], another (256,&nbsp;320], etc. Bucket size
@ -35,6 +41,9 @@ Buckets consist of slot spans, organized as linked lists (see below).
which are also commonly 2MiB. These have to be fully committed / which are also commonly 2MiB. These have to be fully committed /
uncommitted in memory, whereas super pages can be partially committed uncommitted in memory, whereas super pages can be partially committed
with system page granularity. with system page granularity.
* **Extent**: An extent is a run of consecutive super pages (belonging
to a single partition). Extents are to super pages what slot spans are
to slots (see below).
## Slots and Spans ## Slots and Spans
@ -98,6 +107,22 @@ Buckets consist of slot spans, organized as linked lists (see below).
other metadata (e.g. StarScan bitmaps) can bump the starting offset other metadata (e.g. StarScan bitmaps) can bump the starting offset
forward. While this term is entrenched in the code, the team forward. While this term is entrenched in the code, the team
considers it suboptimal and is actively looking for a replacement. considers it suboptimal and is actively looking for a replacement.
* **Allocation Fast Path**: A path taken during an allocation that is
considered fast. Usually means that an allocation request can be
immediately satisfied by grabbing a slot from the freelist of the
first active slot span in the bucket.
* **Allocation Slow Path**: Anything which is not fast (see above).
Can involve
* finding another active slot span in the list,
* provisioning more slots in a slot span,
* bringing back a free (or decommitted) slot span,
* allocating a new slot span, or even
* allocating a new super page.
*** aside
By "slow" we may mean something as simple as extra logic (`if`
statements etc.), or something as costly as system calls.
***
## PartitionAlloc-Everywhere ## PartitionAlloc-Everywhere

View File

@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h" #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -45,6 +46,7 @@ struct PageCharacteristics {
std::atomic<size_t> size; std::atomic<size_t> size;
std::atomic<size_t> shift; std::atomic<size_t> shift;
}; };
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
extern PageCharacteristics page_characteristics; extern PageCharacteristics page_characteristics;
} // namespace partition_alloc::internal } // namespace partition_alloc::internal

View File

@ -25,7 +25,10 @@
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
#include <windows.h> #include <windows.h>
#if defined(PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE)
#include <VersionHelpers.h> // For IsWindows8Point1OrGreater().
#endif #endif
#endif // BUILDFLAG(IS_WIN)
namespace partition_alloc::internal { namespace partition_alloc::internal {
@ -117,10 +120,12 @@ PA_ALWAYS_INLINE size_t PartitionAddressSpace::BRPPoolSize() {
} }
#else #else
PA_ALWAYS_INLINE size_t PartitionAddressSpace::RegularPoolSize() { PA_ALWAYS_INLINE size_t PartitionAddressSpace::RegularPoolSize() {
return kRegularPoolSize; return IsWindows8Point1OrGreater() ? kRegularPoolSize
: kRegularPoolSizeForLegacyWindows;
} }
PA_ALWAYS_INLINE size_t PartitionAddressSpace::BRPPoolSize() { PA_ALWAYS_INLINE size_t PartitionAddressSpace::BRPPoolSize() {
return kBRPPoolSize; return IsWindows8Point1OrGreater() ? kBRPPoolSize
: kBRPPoolSizeForLegacyWindows;
} }
#endif // BUILDFLAG(IS_IOS) #endif // BUILDFLAG(IS_IOS)
#endif // defined(PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE) #endif // defined(PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE)

View File

@ -200,6 +200,16 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
static constexpr size_t kBRPPoolSize = kPoolMaxSize; static constexpr size_t kBRPPoolSize = kPoolMaxSize;
static_assert(base::bits::IsPowerOfTwo(kRegularPoolSize) && static_assert(base::bits::IsPowerOfTwo(kRegularPoolSize) &&
base::bits::IsPowerOfTwo(kBRPPoolSize)); base::bits::IsPowerOfTwo(kBRPPoolSize));
#if defined(PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE)
// We can't afford pool sizes as large as kPoolMaxSize on Windows <8.1 (see
// crbug.com/1101421 and crbug.com/1217759).
static constexpr size_t kRegularPoolSizeForLegacyWindows = 4 * kGiB;
static constexpr size_t kBRPPoolSizeForLegacyWindows = 4 * kGiB;
static_assert(kRegularPoolSizeForLegacyWindows < kRegularPoolSize);
static_assert(kBRPPoolSizeForLegacyWindows < kBRPPoolSize);
static_assert(base::bits::IsPowerOfTwo(kRegularPoolSizeForLegacyWindows) &&
base::bits::IsPowerOfTwo(kBRPPoolSizeForLegacyWindows));
#endif // defined(PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE)
static constexpr size_t kConfigurablePoolMaxSize = kPoolMaxSize; static constexpr size_t kConfigurablePoolMaxSize = kPoolMaxSize;
static constexpr size_t kConfigurablePoolMinSize = 1 * kGiB; static constexpr size_t kConfigurablePoolMinSize = 1 * kGiB;
static_assert(kConfigurablePoolMinSize <= kConfigurablePoolMaxSize); static_assert(kConfigurablePoolMinSize <= kConfigurablePoolMaxSize);

View File

@ -4,6 +4,7 @@
declare_args() { declare_args() {
make_partition_alloc_standalone = false make_partition_alloc_standalone = false
use_freeslot_bitmap = false
} }
# TODO(): move partition allocator's own args defined by # TODO(): move partition allocator's own args defined by

View File

@ -4,17 +4,7 @@
#include "base/allocator/partition_allocator/partition_alloc_base/check.h" #include "base/allocator/partition_allocator/partition_alloc_base/check.h"
#include "build/build_config.h"
// check.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 17000
#endif
#include "base/allocator/partition_allocator/partition_alloc_base/logging.h" #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
#include "build/build_config.h"
namespace partition_alloc::internal::logging { namespace partition_alloc::internal::logging {

View File

@ -4,20 +4,10 @@
#include "base/allocator/partition_allocator/partition_alloc_base/files/file_path.h" #include "base/allocator/partition_allocator/partition_alloc_base/files/file_path.h"
#include "build/build_config.h"
// file_path.h is a widely included header and its size has significant impact
// on build time. Try not to raise this limit unless necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 370000
#endif
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
#include <windows.h> #include <windows.h>

View File

@ -42,7 +42,6 @@
#include <ostream> #include <ostream>
#include <string> #include <string>
#include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
#include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h" #include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h"
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@ -84,13 +83,13 @@ void WriteToFd(int fd, const char* data, size_t length) {
} // namespace } // namespace
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE)
// In DCHECK-enabled Chrome builds, allow the meaning of LOGGING_DCHECK to be // In DCHECK-enabled Chrome builds, allow the meaning of LOGGING_DCHECK to be
// determined at run-time. We default it to INFO, to avoid it triggering // determined at run-time. We default it to INFO, to avoid it triggering
// crashes before the run-time has explicitly chosen the behaviour. // crashes before the run-time has explicitly chosen the behaviour.
PA_COMPONENT_EXPORT(PARTITION_ALLOC) PA_COMPONENT_EXPORT(PARTITION_ALLOC)
logging::LogSeverity LOGGING_DCHECK = LOGGING_INFO; logging::LogSeverity LOGGING_DCHECK = LOGGING_INFO;
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE)
// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have // This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have
// an object of the correct type on the LHS of the unused part of the ternary // an object of the correct type on the LHS of the unused part of the ternary

View File

@ -401,11 +401,11 @@ PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern std::ostream* g_swallow_stream;
// Definitions for DCHECK et al. // Definitions for DCHECK et al.
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE)
PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern LogSeverity LOGGING_DCHECK; PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern LogSeverity LOGGING_DCHECK;
#else #else
constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL; constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL;
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE)
// Redefine the standard assert to use our nice log files // Redefine the standard assert to use our nice log files
#undef assert #undef assert

View File

@ -4,15 +4,6 @@
#include "base/allocator/partition_allocator/partition_alloc_base/time/time.h" #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_LINUX)
// time.h is a widely included header and its size impacts build time.
// Try not to raise this limit unless necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#pragma clang max_tokens_here 490000
#endif // BUILDFLAG(IS_LINUX)
#include <atomic> #include <atomic>
#include <cmath> #include <cmath>
#include <limits> #include <limits>
@ -21,7 +12,6 @@
#include <utility> #include <utility>
#include "base/allocator/partition_allocator/partition_alloc_base/time/time_override.h" #include "base/allocator/partition_allocator/partition_alloc_base/time/time_override.h"
#include "build/build_config.h"
namespace partition_alloc::internal::base { namespace partition_alloc::internal::base {

View File

@ -18,7 +18,6 @@
#include "base/allocator/partition_allocator/partition_alloc_base/time/time_override.h" #include "base/allocator/partition_allocator/partition_alloc_base/time/time_override.h"
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/partition_alloc_notreached.h" #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
#include "build/build_config.h"
// Ensure the Fuchsia and Mac builds do not include this module. Instead, // Ensure the Fuchsia and Mac builds do not include this module. Instead,
// non-POSIX implementation is used for sampling the system clocks. // non-POSIX implementation is used for sampling the system clocks.

View File

@ -0,0 +1,141 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_TYPES_STRONG_ALIAS_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_TYPES_STRONG_ALIAS_H_
#include <type_traits>
#include <utility>
namespace partition_alloc::internal::base {
// A type-safe alternative for a typedef or a 'using' directive.
//
// C++ currently does not support type-safe typedefs, despite multiple proposals
// (ex. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3515.pdf). The
// next best thing is to try and emulate them in library code.
//
// The motivation is to disallow several classes of errors:
//
// using Orange = int;
// using Apple = int;
// Apple apple(2);
// Orange orange = apple; // Orange should not be able to become an Apple.
// Orange x = orange + apple; // Shouldn't add Oranges and Apples.
// if (orange > apple); // Shouldn't compare Apples to Oranges.
// void foo(Orange);
// void foo(Apple); // Redefinition.
// etc.
//
// StrongAlias may instead be used as follows:
//
// using Orange = StrongAlias<class OrangeTag, int>;
// using Apple = StrongAlias<class AppleTag, int>;
// using Banana = StrongAlias<class BananaTag, std::string>;
// Apple apple(2);
// Banana banana("Hello");
// Orange orange = apple; // Does not compile.
// Orange other_orange = orange; // Compiles, types match.
// Orange x = orange + apple; // Does not compile.
// Orange y = Orange(orange.value() + apple.value()); // Compiles.
// Orange z = Orange(banana->size() + *other_orange); // Compiles.
// if (orange > apple); // Does not compile.
// if (orange > other_orange); // Compiles.
// void foo(Orange);
// void foo(Apple); // Compiles into separate overload.
//
// StrongAlias is a zero-cost abstraction, it's compiled away.
//
// TagType is an empty tag class (also called "phantom type") that only serves
// the type system to differentiate between different instantiations of the
// template.
// UnderlyingType may be almost any value type. Note that some methods of the
// StrongAlias may be unavailable (ie. produce elaborate compilation errors when
// used) if UnderlyingType doesn't support them.
//
// StrongAlias only directly exposes comparison operators (for convenient use in
// ordered containers) and a Hasher struct (for unordered_map/set). It's
// impossible, without reflection, to expose all methods of the UnderlyingType
// in StrongAlias's interface. It's also potentially unwanted (ex. you don't
// want to be able to add two StrongAliases that represent socket handles).
// A getter and dereference operators are provided in case you need to access
// the UnderlyingType.
//
// See also
// - //styleguide/c++/blink-c++.md which provides recommendation and examples of
// using StrongAlias<Tag, bool> instead of a bare bool.
// - IdType<...> which provides helpers for specializing StrongAlias to be
// used as an id.
// - TokenType<...> which provides helpers for specializing StrongAlias to be
// used as a wrapper of base::UnguessableToken.
template <typename TagType, typename UnderlyingType>
class StrongAlias {
public:
constexpr StrongAlias() = default;
constexpr explicit StrongAlias(const UnderlyingType& v) : value_(v) {}
constexpr explicit StrongAlias(UnderlyingType&& v) noexcept
: value_(std::move(v)) {}
constexpr UnderlyingType* operator->() { return &value_; }
constexpr const UnderlyingType* operator->() const { return &value_; }
constexpr UnderlyingType& operator*() & { return value_; }
constexpr const UnderlyingType& operator*() const& { return value_; }
constexpr UnderlyingType&& operator*() && { return std::move(value_); }
constexpr const UnderlyingType&& operator*() const&& {
return std::move(value_);
}
constexpr UnderlyingType& value() & { return value_; }
constexpr const UnderlyingType& value() const& { return value_; }
constexpr UnderlyingType&& value() && { return std::move(value_); }
constexpr const UnderlyingType&& value() const&& { return std::move(value_); }
constexpr explicit operator const UnderlyingType&() const& { return value_; }
constexpr bool operator==(const StrongAlias& other) const {
return value_ == other.value_;
}
constexpr bool operator!=(const StrongAlias& other) const {
return value_ != other.value_;
}
constexpr bool operator<(const StrongAlias& other) const {
return value_ < other.value_;
}
constexpr bool operator<=(const StrongAlias& other) const {
return value_ <= other.value_;
}
constexpr bool operator>(const StrongAlias& other) const {
return value_ > other.value_;
}
constexpr bool operator>=(const StrongAlias& other) const {
return value_ >= other.value_;
}
// Hasher to use in std::unordered_map, std::unordered_set, etc.
//
// Example usage:
// using MyType = base::StrongAlias<...>;
// using MySet = std::unordered_set<MyType, typename MyType::Hasher>;
//
// https://google.github.io/styleguide/cppguide.html#std_hash asks to avoid
// defining specializations of `std::hash` - this is why the hasher needs to
// be explicitly specified and why the following code will *not* work:
// using MyType = base::StrongAlias<...>;
// using MySet = std::unordered_set<MyType>; // This won't work.
struct Hasher {
using argument_type = StrongAlias;
using result_type = std::size_t;
result_type operator()(const argument_type& id) const {
return std::hash<UnderlyingType>()(id.value());
}
};
protected:
UnderlyingType value_;
};
} // namespace partition_alloc::internal::base
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_TYPES_STRONG_ALIAS_H_

View File

@ -18,7 +18,7 @@
static_assert(sizeof(void*) == 8, ""); static_assert(sizeof(void*) == 8, "");
#else #else
static_assert(sizeof(void*) != 8, ""); static_assert(sizeof(void*) != 8, "");
#endif #endif // defined(ARCH_CPU_64_BITS) && !BUILDFLAG(IS_NACL)
// PCScan supports 64 bits only. // PCScan supports 64 bits only.
#if defined(PA_HAS_64_BITS_POINTERS) #if defined(PA_HAS_64_BITS_POINTERS)
@ -30,13 +30,21 @@ static_assert(sizeof(void*) != 8, "");
#define PA_STARSCAN_NEON_SUPPORTED #define PA_STARSCAN_NEON_SUPPORTED
#endif #endif
#if BUILDFLAG(IS_IOS) #if defined(PA_HAS_64_BITS_POINTERS) && (BUILDFLAG(IS_IOS) || BUILDFLAG(IS_WIN))
// Use dynamically sized GigaCage. This allows to query the size at run-time, // Use dynamically sized GigaCage. This allows to query the size at run-time,
// before initialization, instead of using a hardcoded constexpr. This is needed // before initialization, instead of using a hardcoded constexpr.
// on iOS because iOS test processes can't handle a large cage (see //
// crbug.com/1250788). // This is needed on iOS because iOS test processes can't handle a large cage
// (see crbug.com/1250788).
//
// This is needed on Windows, because OS versions <8.1 incur commit charge even
// on reserved address space, thus don't handle large cage well (see
// crbug.com/1101421 and crbug.com/1217759).
//
// This setting is specific to 64-bit, as 32-bit has a different implementation.
#define PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE #define PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE
#endif #endif // defined(PA_HAS_64_BITS_POINTERS) &&
// (BUILDFLAG(IS_IOS) || BUILDFLAG(IS_WIN))
#if defined(PA_HAS_64_BITS_POINTERS) && \ #if defined(PA_HAS_64_BITS_POINTERS) && \
(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)) (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID))
@ -90,7 +98,7 @@ static_assert(sizeof(void*) != 8, "");
#define PA_HAS_FAST_MUTEX #define PA_HAS_FAST_MUTEX
#endif #endif
// If set to 1, enables zeroing memory on Free() with roughly 1% probability. // If defined, enables zeroing memory on Free() with roughly 1% probability.
// This applies only to normal buckets, as direct-map allocations are always // This applies only to normal buckets, as direct-map allocations are always
// decommitted. // decommitted.
// TODO(bartekn): Re-enable once PartitionAlloc-Everywhere evaluation is done. // TODO(bartekn): Re-enable once PartitionAlloc-Everywhere evaluation is done.
@ -229,7 +237,7 @@ constexpr bool kUseLazyCommit = false;
// larger slot spans. // larger slot spans.
#if BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) #if BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64))
#define PA_PREFER_SMALLER_SLOT_SPANS #define PA_PREFER_SMALLER_SLOT_SPANS
#endif // BUILDFLAG(IS_LINUX) #endif // BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64))
// Build MTECheckedPtr code. // Build MTECheckedPtr code.
// //

View File

@ -146,6 +146,21 @@ MaxRegularSlotSpanSize() {
return kMaxPartitionPagesPerRegularSlotSpan << PartitionPageShift(); return kMaxPartitionPagesPerRegularSlotSpan << PartitionPageShift();
} }
// The maximum size that is used in an alternate bucket distribution. After this
// threshold, we only have 1 slot per slot-span, so external fragmentation
// doesn't matter. So, using the alternate bucket distribution after this
// threshold has no benefit, and only increases internal fragmentation.
//
// We would like this to be |MaxRegularSlotSpanSize()| on all platforms, but
// this is not constexpr on all platforms, so on other platforms we hardcode it,
// even though this may be too low, e.g. on systems with a page size >4KiB.
constexpr size_t kHighThresholdForAlternateDistribution =
#if PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR
MaxRegularSlotSpanSize();
#else
1 << 16;
#endif
// We reserve virtual address space in 2 MiB chunks (aligned to 2 MiB as well). // We reserve virtual address space in 2 MiB chunks (aligned to 2 MiB as well).
// These chunks are called *super pages*. We do this so that we can store // These chunks are called *super pages*. We do this so that we can store
// metadata in the first few pages of each 2 MiB-aligned section. This makes // metadata in the first few pages of each 2 MiB-aligned section. This makes
@ -242,22 +257,23 @@ constexpr size_t kSuperPageAlignment = kSuperPageSize;
constexpr size_t kSuperPageOffsetMask = kSuperPageAlignment - 1; constexpr size_t kSuperPageOffsetMask = kSuperPageAlignment - 1;
constexpr size_t kSuperPageBaseMask = ~kSuperPageOffsetMask; constexpr size_t kSuperPageBaseMask = ~kSuperPageOffsetMask;
// GigaCage is split into two pools, one which supports BackupRefPtr (BRP) and // GigaCage is generally split into two pools, one which supports BackupRefPtr
// one that doesn't. // (BRP) and one that doesn't.
#if defined(PA_HAS_64_BITS_POINTERS) #if defined(PA_HAS_64_BITS_POINTERS)
// The Configurable Pool is only available in 64-bit mode // The 3rd, Configurable Pool is only available in 64-bit mode.
constexpr size_t kNumPools = 3; constexpr size_t kNumPools = 3;
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) // Maximum GigaCage pool size. With exception of Configurable Pool, it is also
// Special-case macOS. Contrary to other platforms, there is no sandbox limit // the actual size, unless PA_USE_DYNAMICALLY_SIZED_GIGA_CAGE is set, which
// there, meaning that a single renderer could "happily" consume >8GiB. So the // allows to choose a different size at initialization time for certain
// 8GiB pool size is a regression. Make the limit higher on this platform only // configurations.
// to be consistent with previous behavior. See crbug.com/1232567 for details.
// //
// On Linux, reserving memory is not costly, and we have cases where heaps can // Special-case Android and iOS, which incur test failures with larger
// grow to more than 8GiB without being a memory leak. // GigaCage. Regardless, allocating >8GiB with malloc() on these platforms is
constexpr size_t kPoolMaxSize = 16 * kGiB; // unrealistic as of 2022.
#else #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
constexpr size_t kPoolMaxSize = 8 * kGiB; constexpr size_t kPoolMaxSize = 8 * kGiB;
#else
constexpr size_t kPoolMaxSize = 16 * kGiB;
#endif #endif
#else // defined(PA_HAS_64_BITS_POINTERS) #else // defined(PA_HAS_64_BITS_POINTERS)
constexpr size_t kNumPools = 2; constexpr size_t kNumPools = 2;
@ -367,8 +383,10 @@ constexpr size_t kMinDirectMappedDownsize = kMaxBucketed + 1;
// fails. This is a security choice in Chrome, to help making size_t vs int bugs // fails. This is a security choice in Chrome, to help making size_t vs int bugs
// harder to exploit. // harder to exploit.
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t // The definition of MaxDirectMapped does only depend on constants that are
MaxDirectMapped() { // unconditionally constexpr. Therefore it is not necessary to use
// PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR here.
constexpr PA_ALWAYS_INLINE size_t MaxDirectMapped() {
// Subtract kSuperPageSize to accommodate for granularity inside // Subtract kSuperPageSize to accommodate for granularity inside
// PartitionRoot::GetDirectMapReservationSize. // PartitionRoot::GetDirectMapReservationSize.
return (1UL << 31) - kSuperPageSize; return (1UL << 31) - kSuperPageSize;

View File

@ -176,8 +176,6 @@ SlotSpanMetadata<thread_safe>* PartitionDirectMap(
unsigned int flags, unsigned int flags,
size_t raw_size, size_t raw_size,
size_t slot_span_alignment) { size_t slot_span_alignment) {
using ::partition_alloc::internal::ScopedUnlockGuard;
PA_DCHECK((slot_span_alignment >= PartitionPageSize()) && PA_DCHECK((slot_span_alignment >= PartitionPageSize()) &&
base::bits::IsPowerOfTwo(slot_span_alignment)); base::bits::IsPowerOfTwo(slot_span_alignment));
@ -217,6 +215,10 @@ SlotSpanMetadata<thread_safe>* PartitionDirectMap(
PartitionDirectMapExtent<thread_safe>* map_extent = nullptr; PartitionDirectMapExtent<thread_safe>* map_extent = nullptr;
PartitionPage<thread_safe>* page = nullptr; PartitionPage<thread_safe>* page = nullptr;
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
const PartitionTag tag = root->GetNewPartitionTag();
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
{ {
// Getting memory for direct-mapped allocations doesn't interact with the // Getting memory for direct-mapped allocations doesn't interact with the
// rest of the allocator, but takes a long time, as it involves several // rest of the allocator, but takes a long time, as it involves several
@ -410,6 +412,10 @@ SlotSpanMetadata<thread_safe>* PartitionDirectMap(
map_extent->reservation_size = reservation_size; map_extent->reservation_size = reservation_size;
map_extent->padding_for_alignment = padding_for_alignment; map_extent->padding_for_alignment = padding_for_alignment;
map_extent->bucket = &metadata->bucket; map_extent->bucket = &metadata->bucket;
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
DirectMapPartitionTagSetValue(slot_start, tag);
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
} }
root->lock_.AssertAcquired(); root->lock_.AssertAcquired();
@ -687,7 +693,7 @@ PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::AllocNewSuperPage(
return 0; return 0;
// Didn't manage to get a new uncommitted super page -> address space issue. // Didn't manage to get a new uncommitted super page -> address space issue.
::partition_alloc::internal::ScopedUnlockGuard unlock{root->lock_}; ScopedUnlockGuard unlock{root->lock_};
PartitionOutOfMemoryMappingFailure(root, kSuperPageSize); PartitionOutOfMemoryMappingFailure(root, kSuperPageSize);
} }
@ -843,14 +849,13 @@ PartitionBucket<thread_safe>::ProvisionMoreSlotsAndAllocOne(
PA_DCHECK(!slot_span->get_freelist_head()); PA_DCHECK(!slot_span->get_freelist_head());
PA_DCHECK(!slot_span->is_full()); PA_DCHECK(!slot_span->is_full());
size_t size = slot_size;
uintptr_t slot_span_start = uintptr_t slot_span_start =
SlotSpanMetadata<thread_safe>::ToSlotSpanStart(slot_span); SlotSpanMetadata<thread_safe>::ToSlotSpanStart(slot_span);
// If we got here, the first unallocated slot is either partially or fully on // If we got here, the first unallocated slot is either partially or fully on
// an uncommitted page. If the latter, it must be at the start of that page. // an uncommitted page. If the latter, it must be at the start of that page.
uintptr_t return_slot = uintptr_t return_slot =
slot_span_start + (size * slot_span->num_allocated_slots); slot_span_start + (slot_size * slot_span->num_allocated_slots);
uintptr_t next_slot = return_slot + size; uintptr_t next_slot = return_slot + slot_size;
uintptr_t commit_start = base::bits::AlignUp(return_slot, SystemPageSize()); uintptr_t commit_start = base::bits::AlignUp(return_slot, SystemPageSize());
PA_DCHECK(next_slot > commit_start); PA_DCHECK(next_slot > commit_start);
uintptr_t commit_end = base::bits::AlignUp(next_slot, SystemPageSize()); uintptr_t commit_end = base::bits::AlignUp(next_slot, SystemPageSize());
@ -864,7 +869,7 @@ PartitionBucket<thread_safe>::ProvisionMoreSlotsAndAllocOne(
slot_span->num_allocated_slots++; slot_span->num_allocated_slots++;
// Round down, because a slot that doesn't fully fit in the new page(s) isn't // Round down, because a slot that doesn't fully fit in the new page(s) isn't
// provisioned. // provisioned.
size_t slots_to_provision = (commit_end - return_slot) / size; size_t slots_to_provision = (commit_end - return_slot) / slot_size;
slot_span->num_unprovisioned_slots -= slots_to_provision; slot_span->num_unprovisioned_slots -= slots_to_provision;
PA_DCHECK(slot_span->num_allocated_slots + PA_DCHECK(slot_span->num_allocated_slots +
slot_span->num_unprovisioned_slots <= slot_span->num_unprovisioned_slots <=
@ -882,31 +887,33 @@ PartitionBucket<thread_safe>::ProvisionMoreSlotsAndAllocOne(
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
if (PA_LIKELY(size <= kMaxMemoryTaggingSize)) { if (PA_LIKELY(slot_size <= kMaxMemoryTaggingSize)) {
// Ensure the MTE-tag of the memory pointed by |return_slot| is unguessable. // Ensure the MTE-tag of the memory pointed by |return_slot| is unguessable.
TagMemoryRangeRandomly(return_slot, size); TagMemoryRangeRandomly(return_slot, slot_size);
} }
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
PartitionTagSetValue(return_slot, size, root->GetNewPartitionTag()); NormalBucketPartitionTagSetValue(return_slot, slot_size,
root->GetNewPartitionTag());
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
// Add all slots that fit within so far committed pages to the free list. // Add all slots that fit within so far committed pages to the free list.
PartitionFreelistEntry* prev_entry = nullptr; PartitionFreelistEntry* prev_entry = nullptr;
uintptr_t next_slot_end = next_slot + size; uintptr_t next_slot_end = next_slot + slot_size;
size_t free_list_entries_added = 0; size_t free_list_entries_added = 0;
while (next_slot_end <= commit_end) { while (next_slot_end <= commit_end) {
void* next_slot_ptr; void* next_slot_ptr;
if (PA_LIKELY(size <= kMaxMemoryTaggingSize)) { if (PA_LIKELY(slot_size <= kMaxMemoryTaggingSize)) {
// Ensure the MTE-tag of the memory pointed by other provisioned slot is // Ensure the MTE-tag of the memory pointed by other provisioned slot is
// unguessable. They will be returned to the app as is, and the MTE-tag // unguessable. They will be returned to the app as is, and the MTE-tag
// will only change upon calling Free(). // will only change upon calling Free().
next_slot_ptr = TagMemoryRangeRandomly(next_slot, size); next_slot_ptr = TagMemoryRangeRandomly(next_slot, slot_size);
} else { } else {
// No MTE-tagging for larger slots, just cast. // No MTE-tagging for larger slots, just cast.
next_slot_ptr = reinterpret_cast<void*>(next_slot); next_slot_ptr = reinterpret_cast<void*>(next_slot);
} }
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
PartitionTagSetValue(next_slot, size, root->GetNewPartitionTag()); NormalBucketPartitionTagSetValue(next_slot, slot_size,
root->GetNewPartitionTag());
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
auto* entry = PartitionFreelistEntry::EmplaceAndInitNull(next_slot_ptr); auto* entry = PartitionFreelistEntry::EmplaceAndInitNull(next_slot_ptr);
if (!slot_span->get_freelist_head()) { if (!slot_span->get_freelist_head()) {
@ -918,7 +925,7 @@ PartitionBucket<thread_safe>::ProvisionMoreSlotsAndAllocOne(
prev_entry->SetNext(entry); prev_entry->SetNext(entry);
} }
next_slot = next_slot_end; next_slot = next_slot_end;
next_slot_end = next_slot + size; next_slot_end = next_slot + slot_size;
prev_entry = entry; prev_entry = entry;
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
free_list_entries_added++; free_list_entries_added++;
@ -1330,7 +1337,7 @@ uintptr_t PartitionBucket<thread_safe>::SlowPathAlloc(
if (flags & AllocFlags::kReturnNull) if (flags & AllocFlags::kReturnNull)
return 0; return 0;
// See comment in PartitionDirectMap() for unlocking. // See comment in PartitionDirectMap() for unlocking.
::partition_alloc::internal::ScopedUnlockGuard unlock{root->lock_}; ScopedUnlockGuard unlock{root->lock_};
root->OutOfMemory(raw_size); root->OutOfMemory(raw_size);
PA_IMMEDIATE_CRASH(); // Not required, kept as documentation. PA_IMMEDIATE_CRASH(); // Not required, kept as documentation.
} }

View File

@ -241,7 +241,7 @@ PA_ALWAYS_INLINE constexpr uint16_t BucketIndexLookup::GetIndex(size_t size) {
// //
// So, an allocation of size 1.4*2^10 would go into the 1.5*2^10 bucket under // So, an allocation of size 1.4*2^10 would go into the 1.5*2^10 bucket under
// Distribution A, but to the 2^11 bucket under Distribution B. // Distribution A, but to the 2^11 bucket under Distribution B.
if (1 << 8 < size && size < 1 << 19) if (1 << 8 < size && size < kHighThresholdForAlternateDistribution)
return BucketIndexLookup::GetIndexForDenserBuckets(RoundUpSize(size)); return BucketIndexLookup::GetIndexForDenserBuckets(RoundUpSize(size));
return BucketIndexLookup::GetIndexForDenserBuckets(size); return BucketIndexLookup::GetIndexForDenserBuckets(size);
} }

View File

@ -35,8 +35,6 @@ void UnmapNow(uintptr_t reservation_start,
template <bool thread_safe> template <bool thread_safe>
PA_ALWAYS_INLINE void PartitionDirectUnmap( PA_ALWAYS_INLINE void PartitionDirectUnmap(
SlotSpanMetadata<thread_safe>* slot_span) { SlotSpanMetadata<thread_safe>* slot_span) {
using ::partition_alloc::internal::ScopedUnlockGuard;
auto* root = PartitionRoot<thread_safe>::FromSlotSpan(slot_span); auto* root = PartitionRoot<thread_safe>::FromSlotSpan(slot_span);
root->lock_.AssertAcquired(); root->lock_.AssertAcquired();
auto* extent = PartitionDirectMapExtent<thread_safe>::FromSlotSpan(slot_span); auto* extent = PartitionDirectMapExtent<thread_safe>::FromSlotSpan(slot_span);

View File

@ -25,6 +25,7 @@
#include "base/allocator/partition_allocator/partition_bucket.h" #include "base/allocator/partition_allocator/partition_bucket.h"
#include "base/allocator/partition_allocator/partition_freelist_entry.h" #include "base/allocator/partition_allocator/partition_freelist_entry.h"
#include "base/allocator/partition_allocator/partition_tag_bitmap.h" #include "base/allocator/partition_allocator/partition_tag_bitmap.h"
#include "base/allocator/partition_allocator/partition_tag_types.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h" #include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "base/allocator/partition_allocator/starscan/state_bitmap.h" #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
@ -221,6 +222,10 @@ struct SlotSpanMetadata {
PA_ALWAYS_INLINE void SetRawSize(size_t raw_size); PA_ALWAYS_INLINE void SetRawSize(size_t raw_size);
PA_ALWAYS_INLINE size_t GetRawSize() const; PA_ALWAYS_INLINE size_t GetRawSize() const;
// Only meaningful when `this` refers to a slot span in a direct map
// bucket.
PA_ALWAYS_INLINE PartitionTag* DirectMapMTETag();
PA_ALWAYS_INLINE PartitionFreelistEntry* get_freelist_head() const { PA_ALWAYS_INLINE PartitionFreelistEntry* get_freelist_head() const {
return freelist_head; return freelist_head;
} }
@ -334,6 +339,13 @@ struct SubsequentPageMetadata {
// the first one is used to store slot information, but the second one is // the first one is used to store slot information, but the second one is
// available for extra information) // available for extra information)
size_t raw_size; size_t raw_size;
// Specific to when `this` is used in a direct map bucket. Since direct
// maps don't have as many tags as the typical normal bucket slot span,
// we can get away with just hiding the sole tag in here.
//
// See `//base/memory/mtecheckedptr.md` for details.
PartitionTag direct_map_tag;
}; };
// Each partition page has metadata associated with it. The metadata of the // Each partition page has metadata associated with it. The metadata of the
@ -407,6 +419,16 @@ PA_ALWAYS_INLINE PartitionPage<thread_safe>* PartitionSuperPageToMetadataArea(
SystemPageSize()); SystemPageSize());
} }
PA_ALWAYS_INLINE const SubsequentPageMetadata* GetSubsequentPageMetadata(
const PartitionPage<ThreadSafe>* page) {
return &(page + 1)->subsequent_page_metadata;
}
PA_ALWAYS_INLINE SubsequentPageMetadata* GetSubsequentPageMetadata(
PartitionPage<ThreadSafe>* page) {
return &(page + 1)->subsequent_page_metadata;
}
template <bool thread_safe> template <bool thread_safe>
PA_ALWAYS_INLINE PartitionSuperPageExtentEntry<thread_safe>* PA_ALWAYS_INLINE PartitionSuperPageExtentEntry<thread_safe>*
PartitionSuperPageToExtent(uintptr_t super_page) { PartitionSuperPageToExtent(uintptr_t super_page) {
@ -666,16 +688,26 @@ template <bool thread_safe>
PA_ALWAYS_INLINE void SlotSpanMetadata<thread_safe>::SetRawSize( PA_ALWAYS_INLINE void SlotSpanMetadata<thread_safe>::SetRawSize(
size_t raw_size) { size_t raw_size) {
PA_DCHECK(CanStoreRawSize()); PA_DCHECK(CanStoreRawSize());
auto* the_next_page = reinterpret_cast<PartitionPage<thread_safe>*>(this) + 1; auto* subsequent_page_metadata = GetSubsequentPageMetadata(
the_next_page->subsequent_page_metadata.raw_size = raw_size; reinterpret_cast<PartitionPage<thread_safe>*>(this));
subsequent_page_metadata->raw_size = raw_size;
} }
template <bool thread_safe> template <bool thread_safe>
PA_ALWAYS_INLINE size_t SlotSpanMetadata<thread_safe>::GetRawSize() const { PA_ALWAYS_INLINE size_t SlotSpanMetadata<thread_safe>::GetRawSize() const {
PA_DCHECK(CanStoreRawSize()); PA_DCHECK(CanStoreRawSize());
auto* the_next_page = const auto* subsequent_page_metadata = GetSubsequentPageMetadata(
reinterpret_cast<const PartitionPage<thread_safe>*>(this) + 1; reinterpret_cast<const PartitionPage<thread_safe>*>(this));
return the_next_page->subsequent_page_metadata.raw_size; return subsequent_page_metadata->raw_size;
}
template <bool thread_safe>
PA_ALWAYS_INLINE PartitionTag*
SlotSpanMetadata<thread_safe>::DirectMapMTETag() {
PA_DCHECK(bucket->is_direct_mapped());
auto* subsequent_page_metadata = GetSubsequentPageMetadata(
reinterpret_cast<PartitionPage<thread_safe>*>(this));
return &subsequent_page_metadata->direct_map_tag;
} }
template <bool thread_safe> template <bool thread_safe>

View File

@ -278,6 +278,14 @@ void PartitionAllocMallocHookOnAfterForkInChild() {
namespace internal { namespace internal {
namespace {
constexpr size_t kMaxPurgeableSlotsPerSystemPage = 2;
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
MaxPurgeableSlotSize() {
return SystemPageSize() / kMaxPurgeableSlotsPerSystemPage;
}
} // namespace
template <bool thread_safe> template <bool thread_safe>
static size_t PartitionPurgeSlotSpan( static size_t PartitionPurgeSlotSpan(
internal::SlotSpanMetadata<thread_safe>* slot_span, internal::SlotSpanMetadata<thread_safe>* slot_span,
@ -285,7 +293,11 @@ static size_t PartitionPurgeSlotSpan(
auto* root = PartitionRoot<thread_safe>::FromSlotSpan(slot_span); auto* root = PartitionRoot<thread_safe>::FromSlotSpan(slot_span);
const internal::PartitionBucket<thread_safe>* bucket = slot_span->bucket; const internal::PartitionBucket<thread_safe>* bucket = slot_span->bucket;
size_t slot_size = bucket->slot_size; size_t slot_size = bucket->slot_size;
if (slot_size < SystemPageSize() || !slot_span->num_allocated_slots)
// We will do nothing if slot_size is smaller than SystemPageSize() / 2
// because |kMaxSlotCount| will be too large in that case, which leads to
// |slot_usage| using up too much memory.
if (slot_size < MaxPurgeableSlotSize() || !slot_span->num_allocated_slots)
return 0; return 0;
size_t bucket_num_slots = bucket->get_slots_per_span(); size_t bucket_num_slots = bucket->get_slots_per_span();
@ -308,7 +320,7 @@ static size_t PartitionPurgeSlotSpan(
#if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR) #if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR)
constexpr size_t kMaxSlotCount = constexpr size_t kMaxSlotCount =
(PartitionPageSize() * kMaxPartitionPagesPerRegularSlotSpan) / (PartitionPageSize() * kMaxPartitionPagesPerRegularSlotSpan) /
SystemPageSize(); MaxPurgeableSlotSize();
#elif BUILDFLAG(IS_APPLE) || (BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)) #elif BUILDFLAG(IS_APPLE) || (BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64))
// It's better for slot_usage to be stack-allocated and fixed-size, which // It's better for slot_usage to be stack-allocated and fixed-size, which
// demands that its size be constexpr. On IS_APPLE and Linux on arm64, // demands that its size be constexpr. On IS_APPLE and Linux on arm64,
@ -316,10 +328,11 @@ static size_t PartitionPurgeSlotSpan(
// what the run time page size is, kMaxSlotCount can always be simplified // what the run time page size is, kMaxSlotCount can always be simplified
// to this expression. // to this expression.
constexpr size_t kMaxSlotCount = constexpr size_t kMaxSlotCount =
4 * internal::kMaxPartitionPagesPerRegularSlotSpan; 4 * kMaxPurgeableSlotsPerSystemPage *
internal::kMaxPartitionPagesPerRegularSlotSpan;
PA_CHECK(kMaxSlotCount == (PartitionPageSize() * PA_CHECK(kMaxSlotCount == (PartitionPageSize() *
internal::kMaxPartitionPagesPerRegularSlotSpan) / internal::kMaxPartitionPagesPerRegularSlotSpan) /
SystemPageSize()); MaxPurgeableSlotSize());
#endif #endif
PA_DCHECK(bucket_num_slots <= kMaxSlotCount); PA_DCHECK(bucket_num_slots <= kMaxSlotCount);
PA_DCHECK(slot_span->num_unprovisioned_slots < bucket_num_slots); PA_DCHECK(slot_span->num_unprovisioned_slots < bucket_num_slots);
@ -337,10 +350,10 @@ static size_t PartitionPurgeSlotSpan(
// slots are not in use. // slots are not in use.
for (PartitionFreelistEntry* entry = slot_span->get_freelist_head(); entry; for (PartitionFreelistEntry* entry = slot_span->get_freelist_head(); entry;
/**/) { /**/) {
size_t slot_index = size_t slot_number =
(SlotStartPtr2Addr(entry) - slot_span_start) / slot_size; bucket->GetSlotNumber(SlotStartPtr2Addr(entry) - slot_span_start);
PA_DCHECK(slot_index < num_slots); PA_DCHECK(slot_number < num_slots);
slot_usage[slot_index] = 0; slot_usage[slot_number] = 0;
#if !BUILDFLAG(IS_WIN) #if !BUILDFLAG(IS_WIN)
// If we have a slot where the encoded next pointer is 0, we can actually // If we have a slot where the encoded next pointer is 0, we can actually
// discard that entry because touching a discarded page is guaranteed to // discard that entry because touching a discarded page is guaranteed to
@ -348,7 +361,7 @@ static size_t PartitionPurgeSlotSpan(
// effective on big-endian machines because the masking function is // effective on big-endian machines because the masking function is
// negation.) // negation.)
if (entry->IsEncodedNextPtrZero()) if (entry->IsEncodedNextPtrZero())
last_slot = slot_index; last_slot = slot_number;
#endif #endif
entry = entry->GetNext(slot_size); entry = entry->GetNext(slot_size);
} }
@ -367,7 +380,20 @@ static size_t PartitionPurgeSlotSpan(
size_t unprovisioned_bytes = 0; size_t unprovisioned_bytes = 0;
uintptr_t begin_addr = slot_span_start + (num_slots * slot_size); uintptr_t begin_addr = slot_span_start + (num_slots * slot_size);
uintptr_t end_addr = begin_addr + (slot_size * truncated_slots); uintptr_t end_addr = begin_addr + (slot_size * truncated_slots);
begin_addr = RoundUpToSystemPage(begin_addr);
// The slots that do not contain discarded pages should not be included to
// |truncated_slots|. Detects those slots and fixes |truncated_slots| and
// |num_slots| accordingly.
uintptr_t rounded_up_begin_addr = RoundUpToSystemPage(begin_addr);
for (size_t i = 0; i < kMaxPurgeableSlotsPerSystemPage; ++i) {
begin_addr += slot_size;
if (RoundUpToSystemPage(begin_addr) != rounded_up_begin_addr)
break;
--truncated_slots;
++num_slots;
}
begin_addr = rounded_up_begin_addr;
// We round the end address here up and not down because we're at the end of // We round the end address here up and not down because we're at the end of
// a slot span, so we "own" all the way up the page boundary. // a slot span, so we "own" all the way up the page boundary.
end_addr = RoundUpToSystemPage(end_addr); end_addr = RoundUpToSystemPage(end_addr);
@ -415,25 +441,55 @@ static size_t PartitionPurgeSlotSpan(
} }
} }
// Next, walk the slots and for any not in use, consider where the system page if (slot_size < SystemPageSize()) {
// boundaries occur. We can release any system pages back to the system as return discardable_bytes;
// long as we don't interfere with a freelist pointer or an adjacent slot. }
// Next, walk the slots and for any not in use, consider which system pages
// are no longer needed. We can release any system pages back to the system as
// long as we don't interfere with a freelist pointer or an adjacent used
// slot.
for (size_t i = 0; i < num_slots; ++i) { for (size_t i = 0; i < num_slots; ++i) {
if (slot_usage[i]) if (slot_usage[i]) {
continue; continue;
}
// The first address we can safely discard is just after the freelist // The first address we can safely discard is just after the freelist
// pointer. There's one quirk: if the freelist pointer is actually nullptr, // pointer. There's one quirk: if the freelist pointer is actually nullptr,
// we can discard that pointer value too. // we can discard that pointer value too.
uintptr_t begin_addr = slot_span_start + (i * slot_size); uintptr_t begin_addr = slot_span_start + (i * slot_size);
uintptr_t end_addr = begin_addr + slot_size; uintptr_t end_addr = begin_addr + slot_size;
bool can_discard_free_list_pointer = false;
#if !BUILDFLAG(IS_WIN) #if !BUILDFLAG(IS_WIN)
if (i != last_slot) if (i != last_slot) {
begin_addr += sizeof(internal::PartitionFreelistEntry); begin_addr += sizeof(internal::PartitionFreelistEntry);
} else {
can_discard_free_list_pointer = true;
}
#else #else
begin_addr += sizeof(internal::PartitionFreelistEntry); begin_addr += sizeof(internal::PartitionFreelistEntry);
#endif #endif
begin_addr = RoundUpToSystemPage(begin_addr);
uintptr_t rounded_up_begin_addr = RoundUpToSystemPage(begin_addr);
uintptr_t rounded_down_begin_addr = RoundDownToSystemPage(begin_addr);
end_addr = RoundDownToSystemPage(end_addr); end_addr = RoundDownToSystemPage(end_addr);
// |rounded_up_begin_addr| could be greater than |end_addr| only if slot
// size was less than system page size, or if free list pointer crossed the
// page boundary. Neither is possible here.
PA_DCHECK(rounded_up_begin_addr <= end_addr);
if (rounded_down_begin_addr < rounded_up_begin_addr && i != 0 &&
!slot_usage[i - 1] && can_discard_free_list_pointer) {
// This slot contains a partial page in the beginning. The rest of that
// page is contained in the slot[i-1], which is also discardable.
// Therefore we can discard this page.
begin_addr = rounded_down_begin_addr;
} else {
begin_addr = rounded_up_begin_addr;
}
if (begin_addr < end_addr) { if (begin_addr < end_addr) {
size_t partial_slot_bytes = end_addr - begin_addr; size_t partial_slot_bytes = end_addr - begin_addr;
discardable_bytes += partial_slot_bytes; discardable_bytes += partial_slot_bytes;
@ -443,6 +499,7 @@ static size_t PartitionPurgeSlotSpan(
} }
} }
} }
return discardable_bytes; return discardable_bytes;
} }
@ -944,7 +1001,7 @@ bool PartitionRoot<thread_safe>::TryReallocInPlaceForNormalBuckets(
// new size is a significant percentage smaller. We could do the same if we // new size is a significant percentage smaller. We could do the same if we
// determine it is a win. // determine it is a win.
if (AllocationCapacityFromRequestedSize(new_size) != if (AllocationCapacityFromRequestedSize(new_size) !=
AllocationCapacityFromPtr(object)) AllocationCapacityFromSlotStart(slot_start))
return false; return false;
// Trying to allocate |new_size| would use the same amount of underlying // Trying to allocate |new_size| would use the same amount of underlying
@ -1088,7 +1145,7 @@ void PartitionRoot<thread_safe>::PurgeMemory(int flags) {
if (bucket.slot_size == internal::kInvalidBucketSize) if (bucket.slot_size == internal::kInvalidBucketSize)
continue; continue;
if (bucket.slot_size >= internal::SystemPageSize()) if (bucket.slot_size >= internal::MaxPurgeableSlotSize())
internal::PartitionPurgeBucket(&bucket); internal::PartitionPurgeBucket(&bucket);
else else
bucket.SortSlotSpanFreelists(); bucket.SortSlotSpanFreelists();

View File

@ -64,6 +64,7 @@
#include "base/allocator/partition_allocator/partition_page.h" #include "base/allocator/partition_allocator/partition_page.h"
#include "base/allocator/partition_allocator/partition_ref_count.h" #include "base/allocator/partition_allocator/partition_ref_count.h"
#include "base/allocator/partition_allocator/partition_tag.h" #include "base/allocator/partition_allocator/partition_tag.h"
#include "base/allocator/partition_allocator/partition_tag_types.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h" #include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "base/allocator/partition_allocator/starscan/pcscan.h" #include "base/allocator/partition_allocator/starscan/pcscan.h"
#include "base/allocator/partition_allocator/starscan/state_bitmap.h" #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
@ -91,7 +92,9 @@ template <typename Z>
static constexpr bool offset_type = static constexpr bool offset_type =
std::is_integral_v<Z> && sizeof(Z) <= sizeof(ptrdiff_t); std::is_integral_v<Z> && sizeof(Z) <= sizeof(ptrdiff_t);
static constexpr size_t kAllocInfoSize = 1 << 20; // We want this size to be big enough that we have time to start up other
// scripts _before_ we wrap around.
static constexpr size_t kAllocInfoSize = 1 << 24;
struct AllocInfo { struct AllocInfo {
std::atomic<size_t> index{0}; std::atomic<size_t> index{0};
@ -507,7 +510,8 @@ struct PA_ALIGNAS(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot {
PA_ALWAYS_INLINE static size_t GetUsableSize(void* ptr); PA_ALWAYS_INLINE static size_t GetUsableSize(void* ptr);
PA_ALWAYS_INLINE size_t AllocationCapacityFromPtr(void* ptr) const; PA_ALWAYS_INLINE size_t
AllocationCapacityFromSlotStart(uintptr_t slot_start) const;
PA_ALWAYS_INLINE size_t PA_ALWAYS_INLINE size_t
AllocationCapacityFromRequestedSize(size_t size) const; AllocationCapacityFromRequestedSize(size_t size) const;
@ -1187,10 +1191,8 @@ PA_ALWAYS_INLINE void PartitionRoot<thread_safe>::FreeNoHooks(void* object) {
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
if (!root->IsDirectMappedBucket(slot_span->bucket)) { if (!root->IsDirectMappedBucket(slot_span->bucket)) {
size_t slot_size_less_extras =
root->AdjustSizeForExtrasSubtract(slot_span->bucket->slot_size);
partition_alloc::internal::PartitionTagIncrementValue( partition_alloc::internal::PartitionTagIncrementValue(
object, slot_size_less_extras); slot_start, slot_span->bucket->slot_size);
} }
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
@ -1589,6 +1591,7 @@ PA_ALWAYS_INLINE bool PartitionRoot<thread_safe>::TryRecommitSystemPagesForData(
} }
// static // static
//
// Returns the size available to the app. It can be equal or higher than the // Returns the size available to the app. It can be equal or higher than the
// requested size. If higher, the overage won't exceed what's actually usable // requested size. If higher, the overage won't exceed what's actually usable
// by the app without a risk of running out of an allocated region or into // by the app without a risk of running out of an allocated region or into
@ -1614,8 +1617,8 @@ PA_ALWAYS_INLINE size_t PartitionRoot<thread_safe>::GetUsableSize(void* ptr) {
// the same amount of underlying memory. // the same amount of underlying memory.
template <bool thread_safe> template <bool thread_safe>
PA_ALWAYS_INLINE size_t PA_ALWAYS_INLINE size_t
PartitionRoot<thread_safe>::AllocationCapacityFromPtr(void* object) const { PartitionRoot<thread_safe>::AllocationCapacityFromSlotStart(
uintptr_t slot_start = ObjectToSlotStart(object); uintptr_t slot_start) const {
auto* slot_span = SlotSpan::FromSlotStart(slot_start); auto* slot_span = SlotSpan::FromSlotStart(slot_start);
return AdjustSizeForExtrasSubtract(slot_span->bucket->slot_size); return AdjustSizeForExtrasSubtract(slot_span->bucket->slot_size);
} }

View File

@ -13,10 +13,12 @@
#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h" #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h" #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/partition_alloc_forward.h"
#include "base/allocator/partition_allocator/partition_alloc_notreached.h" #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
#include "base/allocator/partition_allocator/partition_cookie.h" #include "base/allocator/partition_allocator/partition_cookie.h"
#include "base/allocator/partition_allocator/partition_page.h" #include "base/allocator/partition_allocator/partition_page.h"
#include "base/allocator/partition_allocator/partition_tag_bitmap.h" #include "base/allocator/partition_allocator/partition_tag_bitmap.h"
#include "base/allocator/partition_allocator/partition_tag_types.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h" #include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -25,19 +27,11 @@ namespace partition_alloc {
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
// Use 8 bits for the partition tag.
// TODO(tasak): add a description about the partition tag.
using PartitionTag = uint8_t;
static_assert( static_assert(
sizeof(PartitionTag) == internal::tag_bitmap::kPartitionTagSize, sizeof(PartitionTag) == internal::tag_bitmap::kPartitionTagSize,
"sizeof(PartitionTag) must be equal to bitmap::kPartitionTagSize."); "sizeof(PartitionTag) must be equal to bitmap::kPartitionTagSize.");
PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(uintptr_t addr) { PA_ALWAYS_INLINE PartitionTag* NormalBucketPartitionTagPointer(uintptr_t addr) {
// TODO(crbug.com/1307514): Add direct map support. For now, just assume
// that direct maps don't have tags.
PA_DCHECK(internal::IsManagedByNormalBuckets(addr));
uintptr_t bitmap_base = uintptr_t bitmap_base =
internal::SuperPageTagBitmapAddr(addr & internal::kSuperPageBaseMask); internal::SuperPageTagBitmapAddr(addr & internal::kSuperPageBaseMask);
const size_t bitmap_end_offset = const size_t bitmap_end_offset =
@ -52,6 +46,23 @@ PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(uintptr_t addr) {
return reinterpret_cast<PartitionTag*>(bitmap_base + offset_in_bitmap); return reinterpret_cast<PartitionTag*>(bitmap_base + offset_in_bitmap);
} }
PA_ALWAYS_INLINE PartitionTag* DirectMapPartitionTagPointer(uintptr_t addr) {
uintptr_t first_super_page = internal::GetDirectMapReservationStart(addr);
PA_DCHECK(first_super_page) << "not managed by a direct map: " << addr;
auto* subsequent_page_metadata = GetSubsequentPageMetadata(
internal::PartitionSuperPageToMetadataArea<internal::ThreadSafe>(
first_super_page));
return &subsequent_page_metadata->direct_map_tag;
}
PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(uintptr_t addr) {
// UNLIKELY because direct maps are far less common than normal buckets.
if (PA_UNLIKELY(internal::IsManagedByDirectMap(addr))) {
return DirectMapPartitionTagPointer(addr);
}
return NormalBucketPartitionTagPointer(addr);
}
PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(const void* ptr) { PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(const void* ptr) {
// Disambiguation: UntagPtr relates to hwardware MTE, and it strips the tag // Disambiguation: UntagPtr relates to hwardware MTE, and it strips the tag
// from the pointer. Whereas, PartitionTagPointer relates to software MTE // from the pointer. Whereas, PartitionTagPointer relates to software MTE
@ -61,12 +72,18 @@ PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(const void* ptr) {
namespace internal { namespace internal {
PA_ALWAYS_INLINE void PartitionTagSetValue(uintptr_t addr, PA_ALWAYS_INLINE void DirectMapPartitionTagSetValue(uintptr_t addr,
size_t size, PartitionTag value) {
PartitionTag value) { *DirectMapPartitionTagPointer(addr) = value;
}
PA_ALWAYS_INLINE void NormalBucketPartitionTagSetValue(uintptr_t slot_start,
size_t size,
PartitionTag value) {
PA_DCHECK((size % tag_bitmap::kBytesPerPartitionTag) == 0); PA_DCHECK((size % tag_bitmap::kBytesPerPartitionTag) == 0);
PA_DCHECK((slot_start % tag_bitmap::kBytesPerPartitionTag) == 0);
size_t tag_count = size >> tag_bitmap::kBytesPerPartitionTagShift; size_t tag_count = size >> tag_bitmap::kBytesPerPartitionTagShift;
PartitionTag* tag_ptr = PartitionTagPointer(addr); PartitionTag* tag_ptr = NormalBucketPartitionTagPointer(slot_start);
if (sizeof(PartitionTag) == 1) { if (sizeof(PartitionTag) == 1) {
memset(tag_ptr, value, tag_count); memset(tag_ptr, value, tag_count);
} else { } else {
@ -75,50 +92,34 @@ PA_ALWAYS_INLINE void PartitionTagSetValue(uintptr_t addr,
} }
} }
PA_ALWAYS_INLINE void PartitionTagSetValue(void* ptr,
size_t size,
PartitionTag value) {
// Disambiguation: UntagPtr relates to hwardware MTE, and it strips the tag
// from the pointer. Whereas, PartitionTagSetValue relates to software MTE
// (i.e. MTECheckedPtr) and it sets the in-memory tag.
PartitionTagSetValue(UntagPtr(ptr), size, value);
}
PA_ALWAYS_INLINE PartitionTag PartitionTagGetValue(void* ptr) { PA_ALWAYS_INLINE PartitionTag PartitionTagGetValue(void* ptr) {
return *PartitionTagPointer(ptr); return *PartitionTagPointer(ptr);
} }
PA_ALWAYS_INLINE void PartitionTagClearValue(void* ptr, size_t size) { PA_ALWAYS_INLINE void PartitionTagIncrementValue(uintptr_t slot_start,
size_t tag_region_size = size >> tag_bitmap::kBytesPerPartitionTagShift size_t size) {
<< tag_bitmap::kPartitionTagSizeShift; PartitionTag tag = *PartitionTagPointer(slot_start);
PA_DCHECK(!memchr(PartitionTagPointer(ptr), 0, tag_region_size));
memset(PartitionTagPointer(ptr), 0, tag_region_size);
}
PA_ALWAYS_INLINE void PartitionTagIncrementValue(void* ptr, size_t size) {
PartitionTag tag = PartitionTagGetValue(ptr);
PartitionTag new_tag = tag; PartitionTag new_tag = tag;
++new_tag; ++new_tag;
new_tag += !new_tag; // Avoid 0. new_tag += !new_tag; // Avoid 0.
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
PA_DCHECK(internal::IsManagedByNormalBuckets(slot_start));
// This verifies that tags for the entire slot have the same value and that // This verifies that tags for the entire slot have the same value and that
// |size| doesn't exceed the slot size. // |size| doesn't exceed the slot size.
size_t tag_count = size >> tag_bitmap::kBytesPerPartitionTagShift; size_t tag_count = size >> tag_bitmap::kBytesPerPartitionTagShift;
PartitionTag* tag_ptr = PartitionTagPointer(ptr); PartitionTag* tag_ptr = PartitionTagPointer(slot_start);
while (tag_count-- > 0) { while (tag_count-- > 0) {
PA_DCHECK(tag == *tag_ptr); PA_DCHECK(tag == *tag_ptr);
tag_ptr++; tag_ptr++;
} }
#endif #endif
PartitionTagSetValue(ptr, size, new_tag); NormalBucketPartitionTagSetValue(slot_start, size, new_tag);
} }
} // namespace internal } // namespace internal
#else // No-op versions #else // No-op versions
using PartitionTag = uint8_t;
PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(void* ptr) { PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(void* ptr) {
PA_NOTREACHED(); PA_NOTREACHED();
return nullptr; return nullptr;
@ -126,15 +127,12 @@ PA_ALWAYS_INLINE PartitionTag* PartitionTagPointer(void* ptr) {
namespace internal { namespace internal {
PA_ALWAYS_INLINE void PartitionTagSetValue(void*, size_t, PartitionTag) {}
PA_ALWAYS_INLINE PartitionTag PartitionTagGetValue(void*) { PA_ALWAYS_INLINE PartitionTag PartitionTagGetValue(void*) {
return 0; return 0;
} }
PA_ALWAYS_INLINE void PartitionTagClearValue(void* ptr, size_t) {} PA_ALWAYS_INLINE void PartitionTagIncrementValue(uintptr_t slot_start,
size_t size) {}
PA_ALWAYS_INLINE void PartitionTagIncrementValue(void* ptr, size_t size) {}
} // namespace internal } // namespace internal

View File

@ -0,0 +1,25 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_TYPES_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_TYPES_H_
#include <cstdint>
// This header defines the types for MTECheckedPtr. Canonical
// documentation available at `//base/memory/raw_ptr_mtecheckedptr.md`.
namespace partition_alloc {
// Use 8 bits for the partition tag. This is the "lower" byte of the
// two top bytes in a 64-bit pointer. The "upper" byte of the same
// is reserved for true ARM MTE.
//
// MTECheckedPtr is not yet compatible with ARM MTE, but it is a
// distant goal to have them coexist.
using PartitionTag = uint8_t;
} // namespace partition_alloc
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_TYPES_H_

View File

@ -568,24 +568,13 @@ PA_ALWAYS_INLINE void ThreadCache::PutInBucket(Bucket& bucket,
// Everything below requires this alignment. // Everything below requires this alignment.
static_assert(internal::kAlignment == 16, ""); static_assert(internal::kAlignment == 16, "");
#if PA_HAS_BUILTIN(__builtin_assume_aligned)
// Cast back to uintptr_t, because we need it for pointer arithmetic. Make
// sure it gets MTE-tagged, as we cast it later to a pointer and dereference.
uintptr_t address_tagged =
reinterpret_cast<uintptr_t>(__builtin_assume_aligned(
internal::SlotStartAddr2Ptr(slot_start), internal::kAlignment));
#else
uintptr_t address_tagged =
reinterpret_cast<uintptr_t>(internal::SlotStartAddr2Ptr(slot_start));
#endif
// The pointer is always 16 bytes aligned, so its start address is always == 0 // The pointer is always 16 bytes aligned, so its start address is always == 0
// % 16. Its distance to the next cacheline is `64 - ((address_tagged & 63) / // % 16. Its distance to the next cacheline is
// 16) * 16`. // `64 - ((slot_start & 63) / 16) * 16`
static_assert( static_assert(
internal::kPartitionCachelineSize == 64, internal::kPartitionCachelineSize == 64,
"The computation below assumes that cache lines are 64 bytes long."); "The computation below assumes that cache lines are 64 bytes long.");
int distance_to_next_cacheline_in_16_bytes = 4 - ((address_tagged >> 4) & 3); int distance_to_next_cacheline_in_16_bytes = 4 - ((slot_start >> 4) & 3);
int slot_size_remaining_in_16_bytes = int slot_size_remaining_in_16_bytes =
#if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT) #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
// When BRP is on in the "previous slot" mode, this slot may have a BRP // When BRP is on in the "previous slot" mode, this slot may have a BRP
@ -601,8 +590,14 @@ PA_ALWAYS_INLINE void ThreadCache::PutInBucket(Bucket& bucket,
static const uint32_t poison_16_bytes[4] = {0xbadbad00, 0xbadbad00, static const uint32_t poison_16_bytes[4] = {0xbadbad00, 0xbadbad00,
0xbadbad00, 0xbadbad00}; 0xbadbad00, 0xbadbad00};
// Already MTE-tagged above, so safe to dereference. // Give a hint to the compiler in hope it'll vectorize the loop.
uint32_t* address_aligned = reinterpret_cast<uint32_t*>(address_tagged); #if PA_HAS_BUILTIN(__builtin_assume_aligned)
void* slot_start_tagged = __builtin_assume_aligned(
internal::SlotStartAddr2Ptr(slot_start), internal::kAlignment);
#else
void* slot_start_tagged = internal::SlotStartAddr2Ptr(slot_start);
#endif
uint32_t* address_aligned = static_cast<uint32_t*>(slot_start_tagged);
for (int i = 0; i < slot_size_remaining_in_16_bytes; i++) { for (int i = 0; i < slot_size_remaining_in_16_bytes; i++) {
// Clang will expand the memcpy to a 16-byte write (movups on x86). // Clang will expand the memcpy to a 16-byte write (movups on x86).
memcpy(address_aligned, poison_16_bytes, sizeof(poison_16_bytes)); memcpy(address_aligned, poison_16_bytes, sizeof(poison_16_bytes));

View File

@ -9,12 +9,13 @@ namespace base {
namespace android { namespace android {
// Defines the state of bindgings with child process. See ChildProcessConnection // Defines the state of bindgings with child process. See ChildProcessConnection
// to see what the bindings are. Note these values are used as array indices. // to see what the bindings are.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
enum class ChildBindingState { enum class ChildBindingState {
UNBOUND, UNBOUND,
WAIVED, WAIVED,
MODERATE, NOT_PERCEPTIBLE,
VISIBLE,
STRONG, STRONG,
MAX_VALUE = STRONG MAX_VALUE = STRONG
}; };

View File

@ -104,12 +104,12 @@ static void JNI_EarlyTraceEvent_RecordEarlyAsyncBeginEvent(
jlong id, jlong id,
jlong time_ns) { jlong time_ns) {
std::string name = ConvertJavaStringToUTF8(env, jname); std::string name = ConvertJavaStringToUTF8(env, jname);
TRACE_EVENT_BEGIN(internal::kJavaTraceCategory, nullptr,
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP_AND_FLAGS0( perfetto::Track(static_cast<uint64_t>(id)),
internal::kJavaTraceCategory, name.c_str(), TimeTicks::FromJavaNanoTime(time_ns),
TRACE_ID_LOCAL(static_cast<uint64_t>(id)), [&](::perfetto::EventContext& ctx) {
TimeTicks::FromJavaNanoTime(time_ns), ctx.event()->set_name(name.c_str());
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); });
} }
static void JNI_EarlyTraceEvent_RecordEarlyAsyncEndEvent( static void JNI_EarlyTraceEvent_RecordEarlyAsyncEndEvent(
@ -118,12 +118,8 @@ static void JNI_EarlyTraceEvent_RecordEarlyAsyncEndEvent(
jlong id, jlong id,
jlong time_ns) { jlong time_ns) {
std::string name = ConvertJavaStringToUTF8(env, jname); std::string name = ConvertJavaStringToUTF8(env, jname);
TRACE_EVENT_END(internal::kJavaTraceCategory,
TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP_AND_FLAGS0( perfetto::Track(static_cast<uint64_t>(id)));
internal::kJavaTraceCategory, name.c_str(),
TRACE_ID_LOCAL(static_cast<uint64_t>(id)),
TimeTicks::FromJavaNanoTime(time_ns),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
} }
bool GetBackgroundStartupTracingFlag() { bool GetBackgroundStartupTracingFlag() {

View File

@ -319,6 +319,10 @@ def _StripGenerics(value):
return ''.join(out) return ''.join(out)
def _NameIsTestOnly(name):
return name.endswith('ForTest') or name.endswith('ForTesting')
class JniParams(object): class JniParams(object):
"""Get JNI related parameters.""" """Get JNI related parameters."""
@ -681,7 +685,8 @@ RE_SCOPED_JNI_TYPES = re.compile('jobject|jclass|jstring|jthrowable|.*Array')
# Regex to match a string like "@CalledByNative public void foo(int bar)". # Regex to match a string like "@CalledByNative public void foo(int bar)".
RE_CALLED_BY_NATIVE = re.compile( RE_CALLED_BY_NATIVE = re.compile(
r'@CalledByNative(?P<Unchecked>(?:Unchecked)?)(?:\("(?P<annotation>.*)"\))?' r'@CalledByNative((?P<Unchecked>(?:Unchecked)?|ForTesting))'
r'(?:\("(?P<annotation>.*)"\))?'
r'(?:\s+@\w+(?:\(.*\))?)*' # Ignore any other annotations. r'(?:\s+@\w+(?:\(.*\))?)*' # Ignore any other annotations.
r'\s+(?P<prefix>(' r'\s+(?P<prefix>('
r'(private|protected|public|static|abstract|final|default|synchronized)' r'(private|protected|public|static|abstract|final|default|synchronized)'
@ -892,8 +897,20 @@ class ProxyHelpers(object):
if not isinstance(hash_b64, str): if not isinstance(hash_b64, str):
hash_b64 = hash_b64.decode() hash_b64 = hash_b64.decode()
hashed_name = ('M' + hash_b64).rstrip('=') long_hash = ('M' + hash_b64).rstrip('=')
return hashed_name[0:ProxyHelpers.MAX_CHARS_FOR_HASHED_NATIVE_METHODS] hashed_name = long_hash[:ProxyHelpers.MAX_CHARS_FOR_HASHED_NATIVE_METHODS]
# If the method is a test-only method, we don't care about saving size on
# the method name, since it shouldn't show up in the binary. Additionally,
# if we just hash the name, our checkers which enforce that we have no
# "ForTesting" methods by checking for the suffix "ForTesting" will miss
# these. We could preserve the name entirely and not hash anything, but
# that risks collisions. So, instead, we just append "ForTesting" to any
# test-only hashes, to ensure we catch any test-only methods that
# shouldn't be in our final binary.
if _NameIsTestOnly(method_name):
return hashed_name + '_ForTesting'
return hashed_name
@staticmethod @staticmethod
def CreateProxyMethodName(fully_qualified_class, old_name, use_hash=False): def CreateProxyMethodName(fully_qualified_class, old_name, use_hash=False):
@ -911,12 +928,18 @@ class ProxyHelpers(object):
return EscapeClassName(fully_qualified_class + '/' + old_name) return EscapeClassName(fully_qualified_class + '/' + old_name)
@staticmethod @staticmethod
def ExtractStaticProxyNatives(fully_qualified_class, contents, ptr_type): def ExtractStaticProxyNatives(fully_qualified_class,
contents,
ptr_type,
include_test_only=True):
methods = [] methods = []
for match in _NATIVE_PROXY_EXTRACTION_REGEX.finditer(contents): for match in _NATIVE_PROXY_EXTRACTION_REGEX.finditer(contents):
interface_body = match.group('interface_body') interface_body = match.group('interface_body')
for method in _EXTRACT_METHODS_REGEX.finditer(interface_body): for method in _EXTRACT_METHODS_REGEX.finditer(interface_body):
name = method.group('name') name = method.group('name')
if not include_test_only and _NameIsTestOnly(name):
continue
params = JniParams.Parse(method.group('params'), use_proxy_types=True) params = JniParams.Parse(method.group('params'), use_proxy_types=True)
return_type = JavaTypeToProxyCast(method.group('return_type')) return_type = JavaTypeToProxyCast(method.group('return_type'))
proxy_name = ProxyHelpers.CreateProxyMethodName(fully_qualified_class, proxy_name = ProxyHelpers.CreateProxyMethodName(fully_qualified_class,
@ -1614,6 +1637,9 @@ See SampleForTests.java for more details.
parser.add_argument('--unchecked_exceptions', parser.add_argument('--unchecked_exceptions',
action='store_true', action='store_true',
help='Do not check that no exceptions were thrown.') help='Do not check that no exceptions were thrown.')
parser.add_argument('--include_test_only',
action='store_true',
help='Whether to maintain ForTesting JNI methods.')
parser.add_argument( parser.add_argument(
'--use_proxy_hash', '--use_proxy_hash',
action='store_true', action='store_true',

View File

@ -62,6 +62,7 @@ class TestOptions(object):
self.always_mangle = False self.always_mangle = False
self.unchecked_exceptions = False self.unchecked_exceptions = False
self.split_name = None self.split_name = None
self.include_test_only = True
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -583,6 +584,9 @@ class TestGenerator(BaseTest):
@CalledByNative @CalledByNative
public List<Bitmap.CompressFormat> getCompressFormatList(); public List<Bitmap.CompressFormat> getCompressFormatList();
@CalledByNativeForTesting
public int[] returnIntArrayForTesting();
""" """
jni_params = jni_generator.JniParams('org/chromium/Foo') jni_params = jni_generator.JniParams('org/chromium/Foo')
jni_params.ExtractImportsAndInnerClasses(test_data) jni_params.ExtractImportsAndInnerClasses(test_data)
@ -822,6 +826,17 @@ class TestGenerator(BaseTest):
env_call=('Void', ''), env_call=('Void', ''),
unchecked=False, unchecked=False,
), ),
CalledByNative(
return_type='int[]',
system_class=False,
static=False,
name='returnIntArrayForTesting',
method_id_var_name='returnIntArrayForTesting',
java_class_name='',
params=[],
env_call=('Void', ''),
unchecked=False,
),
] ]
self.AssertListEquals(golden_called_by_natives, called_by_natives) self.AssertListEquals(golden_called_by_natives, called_by_natives)
h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', [], h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', [],
@ -1386,6 +1401,59 @@ class ProxyTestGenerator(BaseTest):
self.AssertListEquals(_RemoveHashedNames(natives), golden_natives) self.AssertListEquals(_RemoveHashedNames(natives), golden_natives)
def testForTestingKept(self):
test_data = """
class SampleProxyJni {
@NativeMethods
interface Natives {
void fooForTesting();
void fooForTest();
}
}
"""
qualified_clazz = 'org/chromium/example/SampleProxyJni'
natives = jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
qualified_clazz, test_data, 'long', True)
golden_natives = [
NativeMethod(
return_type='void',
static=True,
name='fooForTesting',
params=[],
java_class_name=None,
is_proxy=True,
proxy_name='org_chromium_example_SampleProxyJni_fooForTesting'),
NativeMethod(
return_type='void',
static=True,
name='fooForTest',
params=[],
java_class_name=None,
is_proxy=True,
proxy_name='org_chromium_example_SampleProxyJni_fooForTest'),
]
self.AssertListEquals(_RemoveHashedNames(natives), golden_natives)
def testForTestingRemoved(self):
test_data = """
class SampleProxyJni {
@NativeMethods
interface Natives {
void fooForTesting();
void fooForTest();
}
}
"""
qualified_clazz = 'org/chromium/example/SampleProxyJni'
natives = jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
qualified_clazz, test_data, 'long', False)
self.AssertListEquals(_RemoveHashedNames(natives), [])
def testProxyNativesMainDex(self): def testProxyNativesMainDex(self):
test_data = """ test_data = """
@MainDex @MainDex

View File

@ -41,7 +41,8 @@ def _Generate(java_file_paths,
srcjar_path, srcjar_path,
proxy_opts, proxy_opts,
header_path=None, header_path=None,
namespace=''): namespace='',
include_test_only=True):
"""Generates files required to perform JNI registration. """Generates files required to perform JNI registration.
Generates a srcjar containing a single class, GEN_JNI, that contains all Generates a srcjar containing a single class, GEN_JNI, that contains all
@ -66,7 +67,8 @@ def _Generate(java_file_paths,
_DictForPath, _DictForPath,
use_proxy_hash=proxy_opts.use_hash, use_proxy_hash=proxy_opts.use_hash,
enable_jni_multiplexing=proxy_opts.enable_jni_multiplexing, enable_jni_multiplexing=proxy_opts.enable_jni_multiplexing,
namespace=namespace), java_file_paths): namespace=namespace,
include_test_only=include_test_only), java_file_paths):
if d: if d:
results.append(d) results.append(d)
@ -135,7 +137,8 @@ def _Generate(java_file_paths,
def _DictForPath(path, def _DictForPath(path,
use_proxy_hash=False, use_proxy_hash=False,
enable_jni_multiplexing=False, enable_jni_multiplexing=False,
namespace=''): namespace='',
include_test_only=True):
with open(path) as f: with open(path) as f:
contents = jni_generator.RemoveComments(f.read()) contents = jni_generator.RemoveComments(f.read())
if '@JniIgnoreNatives' in contents: if '@JniIgnoreNatives' in contents:
@ -148,7 +151,8 @@ def _DictForPath(path,
natives += jni_generator.ProxyHelpers.ExtractStaticProxyNatives( natives += jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
fully_qualified_class=fully_qualified_class, fully_qualified_class=fully_qualified_class,
contents=contents, contents=contents,
ptr_type='long') ptr_type='long',
include_test_only=include_test_only)
if len(natives) == 0: if len(natives) == 0:
return None return None
# The namespace for the content is separate from the namespace for the # The namespace for the content is separate from the namespace for the
@ -918,6 +922,9 @@ def main(argv):
'--manual_jni_registration', '--manual_jni_registration',
action='store_true', action='store_true',
help='Manually do JNI registration - required for crazy linker') help='Manually do JNI registration - required for crazy linker')
arg_parser.add_argument('--include_test_only',
action='store_true',
help='Whether to maintain ForTesting JNI methods.')
args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:])) args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:]))
if not args.enable_proxy_mocks and args.require_mocks: if not args.enable_proxy_mocks and args.require_mocks:
@ -948,7 +955,8 @@ def main(argv):
args.srcjar_path, args.srcjar_path,
proxy_opts=proxy_opts, proxy_opts=proxy_opts,
header_path=args.header_path, header_path=args.header_path,
namespace=args.namespace) namespace=args.namespace,
include_test_only=args.include_test_only)
if args.depfile: if args.depfile:
build_utils.WriteDepfile(args.depfile, args.srcjar_path, build_utils.WriteDepfile(args.depfile, args.srcjar_path,

View File

@ -92,13 +92,10 @@ void RunJavaTask(base::android::ScopedJavaGlobalRef<jobject> task,
// JNIEnv is thread specific, but we don't know which thread we'll be run on // JNIEnv is thread specific, but we don't know which thread we'll be run on
// so we must look it up. // so we must look it up.
std::string event_name = base::StrCat({"JniPostTask: ", runnable_class_name}); std::string event_name = base::StrCat({"JniPostTask: ", runnable_class_name});
TRACE_EVENT_BEGIN_WITH_FLAGS0( TRACE_EVENT("toplevel", nullptr, [&](::perfetto::EventContext& ctx) {
"toplevel", event_name.c_str(), ctx.event()->set_name(event_name.c_str());
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); });
JNI_Runnable::Java_Runnable_run(base::android::AttachCurrentThread(), task); JNI_Runnable::Java_Runnable_run(base::android::AttachCurrentThread(), task);
TRACE_EVENT_END_WITH_FLAGS0(
"toplevel", event_name.c_str(),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
} }
} // namespace } // namespace

View File

@ -187,7 +187,7 @@ class TraceEventDataConverter {
// Return saved values to pass to TRACE_EVENT macros. // Return saved values to pass to TRACE_EVENT macros.
const char* name() { return name_.c_str(); } const char* name() { return name_.c_str(); }
const char* arg_name() { return has_arg_ ? "arg" : nullptr; } const char* arg_name() { return has_arg_ ? "arg" : nullptr; }
const char* arg() { return has_arg_ ? arg_.c_str() : nullptr; } const std::string& arg() { return arg_; }
private: private:
std::string name_; std::string name_;
@ -201,17 +201,17 @@ static void JNI_TraceEvent_Instant(JNIEnv* env,
const JavaParamRef<jstring>& jname, const JavaParamRef<jstring>& jname,
const JavaParamRef<jstring>& jarg) { const JavaParamRef<jstring>& jarg) {
TraceEventDataConverter converter(env, jname, jarg); TraceEventDataConverter converter(env, jname, jarg);
if (converter.arg()) { if (converter.arg_name()) {
TRACE_EVENT_INSTANT_WITH_FLAGS1( TRACE_EVENT_INSTANT(internal::kJavaTraceCategory, nullptr,
internal::kJavaTraceCategory, converter.name(), converter.arg_name(), converter.arg(),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY | [&](::perfetto::EventContext& ctx) {
TRACE_EVENT_SCOPE_THREAD, ctx.event()->set_name(converter.name());
converter.arg_name(), converter.arg()); });
} else { } else {
TRACE_EVENT_INSTANT_WITH_FLAGS0( TRACE_EVENT_INSTANT(internal::kJavaTraceCategory, nullptr,
internal::kJavaTraceCategory, converter.name(), [&](::perfetto::EventContext& ctx) {
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY | ctx.event()->set_name(converter.name());
TRACE_EVENT_SCOPE_THREAD); });
} }
} }
@ -233,15 +233,17 @@ static void JNI_TraceEvent_Begin(JNIEnv* env,
const JavaParamRef<jstring>& jname, const JavaParamRef<jstring>& jname,
const JavaParamRef<jstring>& jarg) { const JavaParamRef<jstring>& jarg) {
TraceEventDataConverter converter(env, jname, jarg); TraceEventDataConverter converter(env, jname, jarg);
if (converter.arg()) { if (converter.arg_name()) {
TRACE_EVENT_BEGIN_WITH_FLAGS1( TRACE_EVENT_BEGIN(internal::kJavaTraceCategory, nullptr,
internal::kJavaTraceCategory, converter.name(), converter.arg_name(), converter.arg(),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY, [&](::perfetto::EventContext& ctx) {
converter.arg_name(), converter.arg()); ctx.event()->set_name(converter.name());
});
} else { } else {
TRACE_EVENT_BEGIN_WITH_FLAGS0( TRACE_EVENT_BEGIN(internal::kJavaTraceCategory, nullptr,
internal::kJavaTraceCategory, converter.name(), [&](::perfetto::EventContext& ctx) {
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); ctx.event()->set_name(converter.name());
});
} }
} }
@ -249,52 +251,46 @@ static void JNI_TraceEvent_End(JNIEnv* env,
const JavaParamRef<jstring>& jname, const JavaParamRef<jstring>& jname,
const JavaParamRef<jstring>& jarg) { const JavaParamRef<jstring>& jarg) {
TraceEventDataConverter converter(env, jname, jarg); TraceEventDataConverter converter(env, jname, jarg);
if (converter.arg()) { if (converter.arg_name()) {
TRACE_EVENT_END_WITH_FLAGS1( TRACE_EVENT_END(internal::kJavaTraceCategory, converter.arg_name(),
internal::kJavaTraceCategory, converter.name(), converter.arg());
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY,
converter.arg_name(), converter.arg());
} else { } else {
TRACE_EVENT_END_WITH_FLAGS0( TRACE_EVENT_END(internal::kJavaTraceCategory);
internal::kJavaTraceCategory, converter.name(),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
} }
} }
static void JNI_TraceEvent_BeginToplevel(JNIEnv* env, static void JNI_TraceEvent_BeginToplevel(JNIEnv* env,
const JavaParamRef<jstring>& jtarget) { const JavaParamRef<jstring>& jtarget) {
std::string target = ConvertJavaStringToUTF8(env, jtarget); std::string target = ConvertJavaStringToUTF8(env, jtarget);
TRACE_EVENT_BEGIN_WITH_FLAGS0( TRACE_EVENT_BEGIN(internal::kToplevelTraceCategory, nullptr,
internal::kToplevelTraceCategory, target.c_str(), [&](::perfetto::EventContext& ctx) {
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); ctx.event()->set_name(target.c_str());
});
} }
static void JNI_TraceEvent_EndToplevel(JNIEnv* env, static void JNI_TraceEvent_EndToplevel(JNIEnv* env,
const JavaParamRef<jstring>& jtarget) { const JavaParamRef<jstring>& jtarget) {
std::string target = ConvertJavaStringToUTF8(env, jtarget); std::string target = ConvertJavaStringToUTF8(env, jtarget);
TRACE_EVENT_END_WITH_FLAGS0( TRACE_EVENT_END(internal::kToplevelTraceCategory);
internal::kToplevelTraceCategory, target.c_str(),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
} }
static void JNI_TraceEvent_StartAsync(JNIEnv* env, static void JNI_TraceEvent_StartAsync(JNIEnv* env,
const JavaParamRef<jstring>& jname, const JavaParamRef<jstring>& jname,
jlong jid) { jlong jid) {
TraceEventDataConverter converter(env, jname, nullptr); TraceEventDataConverter converter(env, jname, nullptr);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_FLAGS0( TRACE_EVENT_BEGIN(internal::kJavaTraceCategory, nullptr,
internal::kJavaTraceCategory, converter.name(), perfetto::Track(static_cast<uint64_t>(jid)),
TRACE_ID_LOCAL(static_cast<uint64_t>(jid)), [&](::perfetto::EventContext& ctx) {
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); ctx.event()->set_name(converter.name());
});
} }
static void JNI_TraceEvent_FinishAsync(JNIEnv* env, static void JNI_TraceEvent_FinishAsync(JNIEnv* env,
const JavaParamRef<jstring>& jname, const JavaParamRef<jstring>& jname,
jlong jid) { jlong jid) {
TraceEventDataConverter converter(env, jname, nullptr); TraceEventDataConverter converter(env, jname, nullptr);
TRACE_EVENT_NESTABLE_ASYNC_END_WITH_FLAGS0( TRACE_EVENT_END(internal::kJavaTraceCategory,
internal::kJavaTraceCategory, converter.name(), perfetto::Track(static_cast<uint64_t>(jid)));
TRACE_ID_LOCAL(static_cast<uint64_t>(jid)),
TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY);
} }
} // namespace android } // namespace android

View File

@ -139,11 +139,26 @@ inline internal::UnretainedWrapper<T> Unretained(T* o) {
return internal::UnretainedWrapper<T>(o); return internal::UnretainedWrapper<T>(o);
} }
template <typename T, typename O> template <typename T, typename I>
inline internal::UnretainedWrapper<T> Unretained(const raw_ptr<T, O>& o) { inline internal::UnretainedWrapper<T> Unretained(const raw_ptr<T, I>& o) {
return internal::UnretainedWrapper<T>(o); return internal::UnretainedWrapper<T>(o);
} }
template <typename T, typename I>
inline internal::UnretainedWrapper<T> Unretained(raw_ptr<T, I>&& o) {
return internal::UnretainedWrapper<T>(std::move(o));
}
template <typename T, typename I>
inline auto Unretained(const raw_ref<T, I>& o) {
return internal::UnretainedRefWrapper(o);
}
template <typename T, typename I>
inline auto Unretained(raw_ref<T, I>&& o) {
return internal::UnretainedRefWrapper(std::move(o));
}
// RetainedRef() accepts a ref counted object and retains a reference to it. // RetainedRef() accepts a ref counted object and retains a reference to it.
// When the callback is called, the object is passed as a raw pointer. // When the callback is called, the object is passed as a raw pointer.
// //

View File

@ -19,10 +19,13 @@
#include "base/check.h" #include "base/check.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/raw_scoped_refptr_mismatch_checker.h" #include "base/memory/raw_scoped_refptr_mismatch_checker.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/types/always_false.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "third_party/abseil-cpp/absl/functional/function_ref.h"
#if BUILDFLAG(IS_APPLE) && !HAS_FEATURE(objc_arc) #if BUILDFLAG(IS_APPLE) && !HAS_FEATURE(objc_arc)
#include "base/mac/scoped_block.h" #include "base/mac/scoped_block.h"
@ -75,6 +78,9 @@ struct BindUnwrapTraits;
template <typename Functor, typename BoundArgsTuple, typename SFINAE = void> template <typename Functor, typename BoundArgsTuple, typename SFINAE = void>
struct CallbackCancellationTraits; struct CallbackCancellationTraits;
template <typename Signature>
class FunctionRef;
namespace internal { namespace internal {
template <typename Functor, typename SFINAE = void> template <typename Functor, typename SFINAE = void>
@ -85,13 +91,16 @@ class UnretainedWrapper {
public: public:
explicit UnretainedWrapper(T* o) : ptr_(o) {} explicit UnretainedWrapper(T* o) : ptr_(o) {}
// Trick to only instantiate this constructor if it is used. Otherwise, // Trick to only instantiate these constructors if they are used. Otherwise,
// instantiating UnretainedWrapper with a T that is not supported by // instantiating UnretainedWrapper with a T that is not supported by
// raw_ptr would trigger raw_ptr<T>'s static_assert. // raw_ptr would trigger raw_ptr<T>'s static_assert.
template <typename U = T, typename Option> template <typename U = T, typename I>
// Avoids having a raw_ptr<T> -> T* -> raw_ptr<T> round trip, which // Avoids having a raw_ptr<T> -> T* -> raw_ptr<T> round trip, which
// would trigger the raw_ptr error detector if T* was dangling. // would trigger the raw_ptr error detector if T* was dangling.
explicit UnretainedWrapper(const raw_ptr<U, Option>& o) : ptr_(o) {} explicit UnretainedWrapper(const raw_ptr<U, I>& o) : ptr_(o) {}
template <typename U = T, typename I>
explicit UnretainedWrapper(raw_ptr<U, I>&& o) : ptr_(std::move(o)) {}
T* get() const { return ptr_; } T* get() const { return ptr_; }
private: private:
@ -120,26 +129,46 @@ class UnretainedWrapper {
// std::reference_wrapper<T> and T& do not work, since the reference lifetime is // std::reference_wrapper<T> and T& do not work, since the reference lifetime is
// not safely protected by MiraclePtr. // not safely protected by MiraclePtr.
// //
// UnretainedWrapper<T> and raw_ptr<T> do not work, since BindUnwrapTraits // UnretainedWrapper<T> and raw_ptr<T> do not work, since BindUnwrapTraits would
// would try to pass by T* rather than T&. // try to pass by T* rather than T&.
template <typename T> //
// raw_ref<T> is not used to differentiate between storing a `raw_ref<T>`
// explicitly versus storing a `T&` or `std::ref()`.
template <typename T, bool = raw_ptr_traits::IsSupportedType<T>::value>
class UnretainedRefWrapper { class UnretainedRefWrapper {
public: public:
explicit UnretainedRefWrapper(T& o) : ptr_(std::addressof(o)) {} explicit UnretainedRefWrapper(T& o) : ref_(o) {}
T& get() const { return *ptr_; } T& get() const { return ref_; }
private: private:
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) T& ref_;
// As above.
using ImplType = T*;
#else
using ImplType = std::conditional_t<raw_ptr_traits::IsSupportedType<T>::value,
raw_ptr<T, DanglingUntriaged>,
T*>;
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
ImplType const ptr_;
}; };
#if !defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
// Implementation of UnretainedRefWrapper for `T` where raw_ref<T> is supported.
template <typename T>
class UnretainedRefWrapper<T, true> {
public:
explicit UnretainedRefWrapper(T& o) : ref_(o) {}
T& get() const { return *ref_; }
private:
const raw_ref<T, DanglingUntriaged> ref_;
};
// Implementation of UnretainedRefWrapper for `raw_ref<T>`.
template <typename T, typename I, bool b>
class UnretainedRefWrapper<raw_ref<T, I>, b> {
public:
explicit UnretainedRefWrapper(const raw_ref<T, I>& ref) : ref_(ref) {}
explicit UnretainedRefWrapper(raw_ref<T, I>&& ref) : ref_(std::move(ref)) {}
T& get() const { return *ref_; }
private:
const raw_ref<T, I> ref_;
};
#endif
template <typename T> template <typename T>
class RetainedRefWrapper { class RetainedRefWrapper {
public: public:
@ -208,8 +237,7 @@ class OwnedRefWrapper {
template <typename T> template <typename T>
class PassedWrapper { class PassedWrapper {
public: public:
explicit PassedWrapper(T&& scoper) explicit PassedWrapper(T&& scoper) : scoper_(std::move(scoper)) {}
: is_valid_(true), scoper_(std::move(scoper)) {}
PassedWrapper(PassedWrapper&& other) PassedWrapper(PassedWrapper&& other)
: is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {} : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
T Take() const { T Take() const {
@ -219,7 +247,7 @@ class PassedWrapper {
} }
private: private:
mutable bool is_valid_; mutable bool is_valid_ = true;
mutable T scoper_; mutable T scoper_;
}; };
@ -1048,6 +1076,11 @@ struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
static_assert(!std::is_array_v<std::remove_reference_t<Receiver>>, static_assert(!std::is_array_v<std::remove_reference_t<Receiver>>,
"First bound argument to a method cannot be an array."); "First bound argument to a method cannot be an array.");
static_assert(
!IsRawRefV<DecayedReceiver>,
"Receivers may not be raw_ref<T>. If using a raw_ref<T> here is safe"
" and has no lifetime concerns, use base::Unretained() and document why"
" it's safe.");
static_assert( static_assert(
!IsPointerV<DecayedReceiver> || !IsPointerV<DecayedReceiver> ||
IsRefCountedType<RemovePointerT<DecayedReceiver>>::value, IsRefCountedType<RemovePointerT<DecayedReceiver>>::value,
@ -1356,6 +1389,26 @@ RepeatingCallback<Signature> BindImpl(RepeatingCallback<Signature> callback) {
return callback; return callback;
} }
template <template <typename> class CallbackT, typename Signature>
auto BindImpl(absl::FunctionRef<Signature>, ...) {
static_assert(
AlwaysFalse<Signature>,
"base::Bind{Once,Repeating} require strong ownership: non-owning "
"function references may not bound as the functor due to potential "
"lifetime issues.");
return nullptr;
}
template <template <typename> class CallbackT, typename Signature>
auto BindImpl(FunctionRef<Signature>, ...) {
static_assert(
AlwaysFalse<Signature>,
"base::Bind{Once,Repeating} require strong ownership: non-owning "
"function references may not bound as the functor due to potential "
"lifetime issues.");
return nullptr;
}
} // namespace internal } // namespace internal
// An injection point to control |this| pointer behavior on a method invocation. // An injection point to control |this| pointer behavior on a method invocation.

View File

@ -13,12 +13,12 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback_forward.h" #include "base/callback_forward.h" // IWYU pragma: export
#include "base/callback_internal.h" #include "base/callback_internal.h"
#include "base/check.h" #include "base/check.h"
#include "base/functional/function_ref.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/types/always_false.h" #include "base/types/always_false.h"
#include "third_party/abseil-cpp/absl/functional/function_ref.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Usage documentation // Usage documentation
@ -180,19 +180,19 @@ class OnceCallback<R(Args...)> : public internal::CallbackBase {
template <typename Signature> template <typename Signature>
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator absl::FunctionRef<Signature>() & { operator FunctionRef<Signature>() & {
static_assert( static_assert(
AlwaysFalse<Signature>, AlwaysFalse<Signature>,
"need to convert a base::OnceCallback to absl::FunctionRef? " "need to convert a base::OnceCallback to base::FunctionRef? "
"Please bring up this use case on #cxx (Slack) or cxx@chromium.org."); "Please bring up this use case on #cxx (Slack) or cxx@chromium.org.");
} }
template <typename Signature> template <typename Signature>
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator absl::FunctionRef<Signature>() && { operator FunctionRef<Signature>() && {
static_assert( static_assert(
AlwaysFalse<Signature>, AlwaysFalse<Signature>,
"using base::BindOnce() is not necessary with absl::FunctionRef; is it " "using base::BindOnce() is not necessary with base::FunctionRef; is it "
"possible to use a capturing lambda directly? If not, please bring up " "possible to use a capturing lambda directly? If not, please bring up "
"this use case on #cxx (Slack) or cxx@chromium.org."); "this use case on #cxx (Slack) or cxx@chromium.org.");
} }
@ -310,19 +310,19 @@ class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
template <typename Signature> template <typename Signature>
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator absl::FunctionRef<Signature>() & { operator FunctionRef<Signature>() & {
static_assert( static_assert(
AlwaysFalse<Signature>, AlwaysFalse<Signature>,
"need to convert a base::RepeatingCallback to absl::FunctionRef? " "need to convert a base::RepeatingCallback to base::FunctionRef? "
"Please bring up this use case on #cxx (Slack) or cxx@chromium.org."); "Please bring up this use case on #cxx (Slack) or cxx@chromium.org.");
} }
template <typename Signature> template <typename Signature>
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator absl::FunctionRef<Signature>() && { operator FunctionRef<Signature>() && {
static_assert( static_assert(
AlwaysFalse<Signature>, AlwaysFalse<Signature>,
"using base::BindRepeating() is not necessary with absl::FunctionRef; " "using base::BindRepeating() is not necessary with base::FunctionRef; "
"is it possible to use a capturing lambda directly? If not, please " "is it possible to use a capturing lambda directly? If not, please "
"bring up this use case on #cxx (Slack) or cxx@chromium.org."); "bring up this use case on #cxx (Slack) or cxx@chromium.org.");
} }

View File

@ -4,26 +4,19 @@
#include "base/check.h" #include "base/check.h"
#include "build/build_config.h"
// check.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 17000
#endif
#include "base/check_op.h" #include "base/check_op.h"
#include "base/debug/alias.h" #include "base/debug/alias.h"
#if !BUILDFLAG(IS_NACL) #include "base/debug/debugging_buildflags.h"
#include "base/debug/crash_logging.h"
#endif // !BUILDFLAG(IS_NACL)
#include "base/debug/dump_without_crashing.h" #include "base/debug/dump_without_crashing.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/thread_annotations.h" #include "base/thread_annotations.h"
#include "build/build_config.h" #include "build/build_config.h"
#if !BUILDFLAG(IS_NACL)
#include "base/debug/crash_logging.h"
#endif // !BUILDFLAG(IS_NACL)
#include <atomic> #include <atomic>
namespace logging { namespace logging {
@ -32,24 +25,19 @@ namespace {
// DCHECK_IS_CONFIGURABLE and ENABLE_LOG_ERROR_NOT_REACHED are both interested // DCHECK_IS_CONFIGURABLE and ENABLE_LOG_ERROR_NOT_REACHED are both interested
// in non-FATAL DCHECK()/NOTREACHED() reports. // in non-FATAL DCHECK()/NOTREACHED() reports.
#if defined(DCHECK_IS_CONFIGURABLE) || BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE) || BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
void DCheckDumpOnceWithoutCrashing(LogMessage* log_message) { void DumpOnceWithoutCrashing(LogMessage* log_message) {
// Best-effort gate to prevent multiple DCHECKs from being dumped. This will // Best-effort gate to prevent multiple DCHECKs from being dumped. This will
// race if multiple threads DCHECK at the same time, but we'll eventually stop // race if multiple threads DCHECK at the same time, but we'll eventually stop
// reporting and at most report once per thread. // reporting and at most report once per thread.
static std::atomic<bool> has_dumped = false; static std::atomic<bool> has_dumped = false;
if (!has_dumped.load(std::memory_order_relaxed)) { if (!has_dumped.load(std::memory_order_relaxed)) {
const std::string str = log_message->BuildCrashString();
// Copy the LogMessage message to stack memory to make sure it can be // Copy the LogMessage message to stack memory to make sure it can be
// recovered in crash dumps. // recovered in crash dumps.
// TODO(pbos): Surface DCHECK_MESSAGE well in crash reporting to make this // TODO(pbos): Do we need this for NACL builds or is the crash key set in
// redundant, then remove it. // the caller sufficient?
DEBUG_ALIAS_FOR_CSTR(log_message_str, str.c_str(), 1024); DEBUG_ALIAS_FOR_CSTR(log_message_str,
log_message->BuildCrashString().c_str(), 1024);
#if !BUILDFLAG(IS_NACL)
// Report the log message as DCHECK_MESSAGE in the dump we're about to do.
SCOPED_CRASH_KEY_STRING1024("Logging", "DCHECK_MESSAGE", str);
#endif // !BUILDFLAG(IS_NACL)
// Note that dumping may fail if the crash handler hasn't been set yet. In // Note that dumping may fail if the crash handler hasn't been set yet. In
// that case we want to try again on the next failing DCHECK. // that case we want to try again on the next failing DCHECK.
@ -58,20 +46,36 @@ void DCheckDumpOnceWithoutCrashing(LogMessage* log_message) {
} }
} }
void NotReachedDumpOnceWithoutCrashing(LogMessage* log_message) {
#if !BUILDFLAG(IS_NACL)
SCOPED_CRASH_KEY_STRING1024("Logging", "NOTREACHED_MESSAGE",
log_message->BuildCrashString());
#endif // !BUILDFLAG(IS_NACL)
DumpOnceWithoutCrashing(log_message);
}
class NotReachedLogMessage : public LogMessage { class NotReachedLogMessage : public LogMessage {
public: public:
using LogMessage::LogMessage; using LogMessage::LogMessage;
~NotReachedLogMessage() override { ~NotReachedLogMessage() override {
if (severity() != logging::LOGGING_FATAL) if (severity() != logging::LOGGING_FATAL)
DCheckDumpOnceWithoutCrashing(this); NotReachedDumpOnceWithoutCrashing(this);
} }
}; };
#else #else
using NotReachedLogMessage = LogMessage; using NotReachedLogMessage = LogMessage;
#endif // defined(DCHECK_IS_CONFIGURABLE) || #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE) ||
// BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED) // BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
void DCheckDumpOnceWithoutCrashing(LogMessage* log_message) {
#if !BUILDFLAG(IS_NACL)
SCOPED_CRASH_KEY_STRING1024("Logging", "DCHECK_MESSAGE",
log_message->BuildCrashString());
#endif // !BUILDFLAG(IS_NACL)
DumpOnceWithoutCrashing(log_message);
}
class DCheckLogMessage : public LogMessage { class DCheckLogMessage : public LogMessage {
public: public:
@ -109,7 +113,7 @@ using DCheckWin32ErrorLogMessage = Win32ErrorLogMessage;
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
using DCheckErrnoLogMessage = ErrnoLogMessage; using DCheckErrnoLogMessage = ErrnoLogMessage;
#endif // BUILDFLAG(IS_WIN) #endif // BUILDFLAG(IS_WIN)
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
} // namespace } // namespace

View File

@ -10,6 +10,7 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/dcheck_is_on.h" #include "base/dcheck_is_on.h"
#include "base/debug/debugging_buildflags.h"
#include "base/immediate_crash.h" #include "base/immediate_crash.h"
// This header defines the CHECK, DCHECK, and DPCHECK macros. // This header defines the CHECK, DCHECK, and DPCHECK macros.
@ -98,7 +99,8 @@ class BASE_EXPORT CheckError {
LogMessage* const log_message_; LogMessage* const log_message_;
}; };
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) #if defined(OFFICIAL_BUILD) && defined(NDEBUG) && \
!BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// Discard log strings to reduce code bloat. // Discard log strings to reduce code bloat.
// //

View File

@ -34,7 +34,7 @@
// //
// `CHECK_IS_TEST` is thread safe. // `CHECK_IS_TEST` is thread safe.
#define CHECK_IS_TEST() base::internal::check_is_test_impl(); #define CHECK_IS_TEST() base::internal::check_is_test_impl()
namespace base::internal { namespace base::internal {
BASE_EXPORT void check_is_test_impl(); BASE_EXPORT void check_is_test_impl();

View File

@ -4,13 +4,6 @@
#include "base/check_op.h" #include "base/check_op.h"
// check_op.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 390000
#endif
#include <string.h> #include <string.h>
#include <cstdio> #include <cstdio>

View File

@ -12,6 +12,7 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/check.h" #include "base/check.h"
#include "base/dcheck_is_on.h" #include "base/dcheck_is_on.h"
#include "base/debug/debugging_buildflags.h"
#include "base/template_util.h" #include "base/template_util.h"
// This header defines the (DP)CHECK_EQ etc. macros. // This header defines the (DP)CHECK_EQ etc. macros.
@ -139,7 +140,8 @@ class CheckOpResult {
char* message_ = nullptr; char* message_ = nullptr;
}; };
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) #if defined(OFFICIAL_BUILD) && defined(NDEBUG) && \
!BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// Discard log strings to reduce code bloat. // Discard log strings to reduce code bloat.
#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2)) #define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))

View File

@ -170,6 +170,8 @@
#endif #endif
// DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks. // DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks.
// Security Note: if you just need to allow calling of dlsym functions use
// DISABLE_CFI_DLSYM.
#if !defined(DISABLE_CFI_ICALL) #if !defined(DISABLE_CFI_ICALL)
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
// Windows also needs __declspec(guard(nocf)). // Windows also needs __declspec(guard(nocf)).
@ -182,6 +184,21 @@
#define DISABLE_CFI_ICALL #define DISABLE_CFI_ICALL
#endif #endif
// DISABLE_CFI_DLSYM -- applies DISABLE_CFI_ICALL on platforms where dlsym
// functions must be called. Retains CFI checks on platforms where loaded
// modules participate in CFI (e.g. Windows).
#if !defined(DISABLE_CFI_DLSYM)
#if BUILDFLAG(IS_WIN)
// Windows modules register functions when loaded so can be checked by CFG.
#define DISABLE_CFI_DLSYM
#else
#define DISABLE_CFI_DLSYM DISABLE_CFI_ICALL
#endif
#endif
#if !defined(DISABLE_CFI_DLSYM)
#define DISABLE_CFI_DLSYM
#endif
// Macro useful for writing cross-platform function pointers. // Macro useful for writing cross-platform function pointers.
#if !defined(CDECL) #if !defined(CDECL)
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
@ -389,4 +406,13 @@ inline constexpr bool AnalyzerAssumeTrue(bool arg) {
#define GSL_POINTER #define GSL_POINTER
#endif #endif
// Adds the "logically_const" tag to a symbol's mangled name, which can be
// recognized by the "Mutable Constants" check
// (https://chromium.googlesource.com/chromium/src/+/main/docs/speed/binary_size/android_binary_size_trybot.md#Mutable-Constants).
#if defined(COMPILER_GCC) || defined(__clang__)
#define LOGICALLY_CONST [[gnu::abi_tag("logically_const")]]
#else
#define LOGICALLY_CONST
#endif
#endif // BASE_COMPILER_SPECIFIC_H_ #endif // BASE_COMPILER_SPECIFIC_H_

View File

@ -4,13 +4,6 @@
#include "base/containers/flat_tree.h" #include "base/containers/flat_tree.h"
// flat_tree.h is a widely included header and its size has significant impact
// on build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 370000
#endif
namespace base { namespace base {
sorted_unique_t sorted_unique; sorted_unique_t sorted_unique;

View File

@ -286,7 +286,10 @@ class GSL_POINTER span : public internal::ExtentStorage<Extent> {
typename End, typename End,
typename = internal::EnableIfCompatibleContiguousIterator<It, T>, typename = internal::EnableIfCompatibleContiguousIterator<It, T>,
typename = std::enable_if_t<!std::is_convertible<End, size_t>::value>> typename = std::enable_if_t<!std::is_convertible<End, size_t>::value>>
constexpr span(It begin, End end) noexcept : span(begin, end - begin) { constexpr span(It begin, End end) noexcept
// Subtracting two iterators gives a ptrdiff_t, but the result should be
// non-negative: see CHECK below.
: span(begin, static_cast<size_t>(end - begin)) {
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used. // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
CHECK(begin <= end); CHECK(begin <= end);
} }

View File

@ -4,13 +4,6 @@
#include "base/debug/alias.h" #include "base/debug/alias.h"
// This is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 250
#endif
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
namespace base { namespace base {

View File

@ -4,8 +4,10 @@
#include "base/debug/crash_logging.h" #include "base/debug/crash_logging.h"
namespace base { #include "base/strings/string_piece.h"
namespace debug { #include "build/build_config.h"
namespace base::debug {
namespace { namespace {
@ -18,6 +20,24 @@ CrashKeyString* AllocateCrashKeyString(const char name[],
if (!g_crash_key_impl) if (!g_crash_key_impl)
return nullptr; return nullptr;
// TODO(https://crbug.com/1341077): It would be great if the DCHECKs below
// could also be enabled on Android, but debugging tryjob failures was a bit
// difficult... :-/
#if DCHECK_IS_ON() && !BUILDFLAG(IS_ANDROID)
base::StringPiece name_piece = name;
// Some `CrashKeyImplementation`s reserve certain characters and disallow
// using them in crash key names. See also https://crbug.com/1341077.
DCHECK_EQ(base::StringPiece::npos, name_piece.find(':'))
<< "; name_piece = " << name_piece;
// Some `CrashKeyImplementation`s support only short crash key names (e.g. see
// the DCHECK in crash_reporter::internal::CrashKeyStringImpl::Set).
// Enforcing this restrictions here ensures that crash keys will work for all
// `CrashKeyStringImpl`s.
DCHECK_LT(name_piece.size(), 40u);
#endif
return g_crash_key_impl->Allocate(name, value_length); return g_crash_key_impl->Allocate(name, value_length);
} }
@ -60,5 +80,4 @@ void SetCrashKeyImplementation(std::unique_ptr<CrashKeyImplementation> impl) {
g_crash_key_impl = impl.release(); g_crash_key_impl = impl.release();
} }
} // namespace debug } // namespace base::debug
} // namespace base

View File

@ -4,13 +4,6 @@
#include "base/feature_list.h" #include "base/feature_list.h"
// feature_list.h is a widely included header and its size impacts build
// time. Try not to raise this limit unless necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 600000
#endif
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -51,6 +44,16 @@ FeatureList* g_feature_list_instance = nullptr;
// which Feature that accessor was for, if so. // which Feature that accessor was for, if so.
const Feature* g_initialized_from_accessor = nullptr; const Feature* g_initialized_from_accessor = nullptr;
// Controls whether a feature's override state will be cached in
// `base::Feature::cached_value`. This field and the associated `base::Feature`
// only exist to measure the impact of the caching on different performance
// metrics.
// TODO(crbug.com/1341292): Remove this global and this feature once the gains
// are measured.
bool g_cache_override_state = false;
const base::Feature kCacheFeatureOverrideState{
"CacheFeatureOverrideState", base::FEATURE_ENABLED_BY_DEFAULT};
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
// Tracks whether the use of base::Feature is allowed for this module. // Tracks whether the use of base::Feature is allowed for this module.
// See ForbidUseForCurrentModule(). // See ForbidUseForCurrentModule().
@ -115,17 +118,18 @@ bool IsValidFeatureOrFieldTrialName(StringPiece name) {
return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos; return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
} }
// Splits |first| into two parts by the |separator| where the first part will be // Splits |text| into two parts by the |separator| where the first part will be
// returned updated in |first| and the second part will be returned as |second|. // returned updated in |first| and the second part will be returned as |second|.
// This function returns false if there is more than one |separator| in |first|. // This function returns false if there is more than one |separator| in |first|.
// If there is no |separator| presented in |first|, this function will not // If there is no |separator| presented in |first|, this function will not
// modify |first| and |second|. It's used for splitting the |enable_features| // modify |first| and |second|. It's used for splitting the |enable_features|
// flag into feature name, field trial name and feature parameters. // flag into feature name, field trial name and feature parameters.
bool SplitIntoTwo(const std::string& separator, bool SplitIntoTwo(StringPiece text,
StringPiece separator,
StringPiece* first, StringPiece* first,
std::string* second) { std::string* second) {
std::vector<StringPiece> parts = std::vector<StringPiece> parts =
SplitStringPiece(*first, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL); SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL);
if (parts.size() == 2) { if (parts.size() == 2) {
*second = std::string(parts[1]); *second = std::string(parts[1]);
} else if (parts.size() > 2) { } else if (parts.size() > 2) {
@ -150,31 +154,21 @@ bool ParseEnableFeatures(const std::string& enable_features,
std::vector<std::string> enable_features_list; std::vector<std::string> enable_features_list;
std::vector<std::string> force_fieldtrials_list; std::vector<std::string> force_fieldtrials_list;
std::vector<std::string> force_fieldtrial_params_list; std::vector<std::string> force_fieldtrial_params_list;
for (auto& enable_feature : for (const auto& enable_feature :
FeatureList::SplitFeatureListString(enable_features)) { FeatureList::SplitFeatureListString(enable_features)) {
// First, check whether ":" is present. If true, feature parameters were std::string feature_name;
// set for this feature.
std::string feature_params;
if (!SplitIntoTwo(":", &enable_feature, &feature_params))
return false;
// Then, check whether "." is present. If true, a group was specified for
// this feature.
std::string group;
if (!SplitIntoTwo(".", &enable_feature, &group))
return false;
// Finally, check whether "<" is present. If true, a study was specified for
// this feature.
std::string study; std::string study;
if (!SplitIntoTwo("<", &enable_feature, &study)) std::string group;
std::string feature_params;
if (!FeatureList::ParseEnableFeatureString(
enable_feature, &feature_name, &study, &group, &feature_params)) {
return false; return false;
}
const std::string feature_name(enable_feature);
// If feature params were set but group and study weren't, associate the // If feature params were set but group and study weren't, associate the
// feature and its feature params to a synthetic field trial as the // feature and its feature params to a synthetic field trial as the
// feature params only make sense when it's combined with a field trial. // feature params only make sense when it's combined with a field trial.
if (!feature_params.empty()) { if (!feature_params.empty()) {
study = study.empty() ? "Study" + feature_name : study;
group = group.empty() ? "Group" + feature_name : group;
force_fieldtrials_list.push_back(study + "/" + group); force_fieldtrials_list.push_back(study + "/" + group);
force_fieldtrial_params_list.push_back(study + "." + group + ":" + force_fieldtrial_params_list.push_back(study + "." + group + ":" +
feature_params); feature_params);
@ -191,12 +185,25 @@ bool ParseEnableFeatures(const std::string& enable_features,
return true; return true;
} }
std::pair<FeatureList::OverrideState, uint16_t> UnpackFeatureCache(
uint32_t packed_cache_value) {
return std::make_pair(
static_cast<FeatureList::OverrideState>(packed_cache_value >> 24),
packed_cache_value & 0xFFFF);
}
uint32_t PackFeatureCache(FeatureList::OverrideState override_state,
uint32_t caching_context) {
return (static_cast<uint32_t>(override_state) << 24) |
(caching_context & 0xFFFF);
}
} // namespace } // namespace
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
const Feature kDCheckIsFatalFeature{"DcheckIsFatal", const Feature kDCheckIsFatalFeature{"DcheckIsFatal",
FEATURE_DISABLED_BY_DEFAULT}; FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
FeatureList::FeatureList() = default; FeatureList::FeatureList() = default;
@ -369,8 +376,10 @@ void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) {
} }
void FeatureList::GetFeatureOverrides(std::string* enable_overrides, void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
std::string* disable_overrides) const { std::string* disable_overrides,
GetFeatureOverridesImpl(enable_overrides, disable_overrides, false); bool include_group_name) const {
GetFeatureOverridesImpl(enable_overrides, disable_overrides, false,
include_group_name);
} }
void FeatureList::GetCommandLineFeatureOverrides( void FeatureList::GetCommandLineFeatureOverrides(
@ -423,6 +432,45 @@ std::vector<StringPiece> FeatureList::SplitFeatureListString(
return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
} }
// static
bool FeatureList::ParseEnableFeatureString(StringPiece enable_feature,
std::string* feature_name,
std::string* study_name,
std::string* group_name,
std::string* params) {
StringPiece first;
// First, check whether ":" is present. If true, feature parameters were
// set for this feature.
std::string feature_params;
if (!SplitIntoTwo(enable_feature, ":", &first, &feature_params))
return false;
// Then, check whether "." is present. If true, a group was specified for
// this feature.
std::string group;
if (!SplitIntoTwo(first, ".", &first, &group))
return false;
// Finally, check whether "<" is present. If true, a study was specified for
// this feature.
std::string study;
if (!SplitIntoTwo(first, "<", &first, &study))
return false;
std::string enable_feature_name(first);
// If feature params were set but group and study weren't, associate the
// feature and its feature params to a synthetic field trial as the
// feature params only make sense when it's combined with a field trial.
if (!feature_params.empty()) {
study = study.empty() ? "Study" + enable_feature_name : study;
group = group.empty() ? "Group" + enable_feature_name : group;
}
feature_name->swap(enable_feature_name);
study_name->swap(study);
group_name->swap(group);
params->swap(feature_params);
return true;
}
// static // static
bool FeatureList::InitializeInstance(const std::string& enable_features, bool FeatureList::InitializeInstance(const std::string& enable_features,
const std::string& disable_features) { const std::string& disable_features) {
@ -484,9 +532,12 @@ void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
ConfigureRandBytesFieldTrial(); ConfigureRandBytesFieldTrial();
#endif #endif
g_cache_override_state =
base::FeatureList::IsEnabled(kCacheFeatureOverrideState);
base::sequence_manager::internal::WorkQueue::ConfigureCapacityFieldTrial(); base::sequence_manager::internal::WorkQueue::ConfigureCapacityFieldTrial();
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// Update the behaviour of LOGGING_DCHECK to match the Feature configuration. // Update the behaviour of LOGGING_DCHECK to match the Feature configuration.
// DCHECK is also forced to be FATAL if we are running a death-test. // DCHECK is also forced to be FATAL if we are running a death-test.
// TODO(crbug.com/1057995#c11): --gtest_internal_run_death_test doesn't // TODO(crbug.com/1057995#c11): --gtest_internal_run_death_test doesn't
@ -501,7 +552,7 @@ void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
} else { } else {
logging::LOGGING_DCHECK = logging::LOG_INFO; logging::LOGGING_DCHECK = logging::LOG_INFO;
} }
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
} }
// static // static
@ -529,6 +580,10 @@ void FeatureList::ForbidUseForCurrentModule() {
#endif // DCHECK_IS_ON() #endif // DCHECK_IS_ON()
} }
void FeatureList::SetCachingContextForTesting(uint16_t caching_context) {
caching_context_ = caching_context;
}
void FeatureList::FinalizeInitialization() { void FeatureList::FinalizeInitialization() {
DCHECK(!initialized_); DCHECK(!initialized_);
// Store the field trial list pointer for DCHECKing. // Store the field trial list pointer for DCHECKing.
@ -563,7 +618,32 @@ FeatureList::OverrideState FeatureList::GetOverrideState(
DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name; DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
DCHECK(CheckFeatureIdentity(feature)) << feature.name; DCHECK(CheckFeatureIdentity(feature)) << feature.name;
return GetOverrideStateByFeatureName(feature.name); // If caching is disabled, always perform the full lookup.
if (!g_cache_override_state)
return GetOverrideStateByFeatureName(feature.name);
uint32_t current_cache_value =
feature.cached_value.load(std::memory_order_relaxed);
auto unpacked = UnpackFeatureCache(current_cache_value);
if (unpacked.second == caching_context_)
return unpacked.first;
OverrideState state = GetOverrideStateByFeatureName(feature.name);
uint32_t new_cache_value = PackFeatureCache(state, caching_context_);
// Update the cache with the new value.
// In non-test code, this value can be in one of 2 states: either it's unset,
// or another thread has updated it to the same value we're about to write.
// Because of this, a plain `store` yields the correct result in all cases.
// In test code, it's possible for a different thread to have installed a new
// `ScopedFeatureList` and written a value that's different than the one we're
// about to write, although that would be a thread safety violation already
// and such tests should be fixed.
feature.cached_value.store(new_cache_value, std::memory_order_relaxed);
return state;
} }
FeatureList::OverrideState FeatureList::GetOverrideStateByFeatureName( FeatureList::OverrideState FeatureList::GetOverrideStateByFeatureName(
@ -690,7 +770,8 @@ void FeatureList::RegisterOverride(StringPiece feature_name,
void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides, void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides,
std::string* disable_overrides, std::string* disable_overrides,
bool command_line_only) const { bool command_line_only,
bool include_group_name) const {
DCHECK(initialized_); DCHECK(initialized_);
// Check that the FieldTrialList this is associated with, if any, is the // Check that the FieldTrialList this is associated with, if any, is the
@ -730,8 +811,13 @@ void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides,
target_list->push_back('*'); target_list->push_back('*');
target_list->append(entry.first); target_list->append(entry.first);
if (entry.second.field_trial) { if (entry.second.field_trial) {
auto* const field_trial = entry.second.field_trial;
target_list->push_back('<'); target_list->push_back('<');
target_list->append(entry.second.field_trial->trial_name()); target_list->append(field_trial->trial_name());
if (include_group_name) {
target_list->push_back('.');
target_list->append(field_trial->GetGroupNameWithoutActivation());
}
} }
} }
} }

View File

@ -5,6 +5,7 @@
#ifndef BASE_FEATURE_LIST_H_ #ifndef BASE_FEATURE_LIST_H_
#define BASE_FEATURE_LIST_H_ #define BASE_FEATURE_LIST_H_
#include <atomic>
#include <functional> #include <functional>
#include <map> #include <map>
#include <memory> #include <memory>
@ -13,6 +14,7 @@
#include <vector> #include <vector>
#include "base/base_export.h" #include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/dcheck_is_on.h" #include "base/dcheck_is_on.h"
#include "base/feature_list_buildflags.h" #include "base/feature_list_buildflags.h"
@ -43,7 +45,21 @@ enum FeatureState {
// file static. It should never be used as a constexpr as it breaks // file static. It should never be used as a constexpr as it breaks
// pointer-based identity lookup. // pointer-based identity lookup.
// Note: New code should use CONSTINIT on the base::Feature declaration. // Note: New code should use CONSTINIT on the base::Feature declaration.
struct BASE_EXPORT Feature { //
// Making Feature constants mutable allows them to contain a mutable member to
// cache their override state, while still remaining declared as const. This
// cache member allows for significantly faster IsEnabled() checks.
// The "Mutable Constants" check
// (https://chromium.googlesource.com/chromium/src/+/main/docs/speed/binary_size/android_binary_size_trybot.md#Mutable-Constants)
// detects this, because this generally means that a readonly symbol is put in
// writable memory when readonly memory would be more efficient in terms of
// space. Declaring as LOGICALLY_CONST adds a recognizable pattern to all
// Feature constant mangled names, which the "Mutable Constants" can use to
// ignore the symbols declared as such. The performance gains of the cache are
// large enough that it is worth the tradeoff to have the symbols in
// non-readonly memory, therefore requiring a bypass of the "Mutable Constants"
// check.
struct BASE_EXPORT LOGICALLY_CONST Feature {
constexpr Feature(const char* name, FeatureState default_state) constexpr Feature(const char* name, FeatureState default_state)
: name(name), default_state(default_state) { : name(name), default_state(default_state) {
#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) #if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
@ -53,6 +69,14 @@ struct BASE_EXPORT Feature {
} }
#endif // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX) #endif // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
} }
// This object needs to be copyable because of some signatures in
// ScopedFeatureList, but generally isn't copied anywhere except unit tests.
// The `cached_value` doesn't get copied and copies will trigger a lookup if
// their state is queried.
Feature(const Feature& other)
: name(other.name), default_state(other.default_state), cached_value(0) {}
// The name of the feature. This should be unique to each feature and is used // The name of the feature. This should be unique to each feature and is used
// for enabling/disabling features via command line flags and experiments. // for enabling/disabling features via command line flags and experiments.
// It is strongly recommended to use CamelCase style for feature names, e.g. // It is strongly recommended to use CamelCase style for feature names, e.g.
@ -63,14 +87,35 @@ struct BASE_EXPORT Feature {
// NOTE: The actual runtime state may be different, due to a field trial or a // NOTE: The actual runtime state may be different, due to a field trial or a
// command line switch. // command line switch.
const FeatureState default_state; const FeatureState default_state;
private:
friend class FeatureList;
// A packed value where the first 8 bits represent the `OverrideState` of this
// feature, and the last 16 bits are a caching context ID used to allow
// ScopedFeatureLists to invalidate these cached values in testing. A value of
// 0 in the caching context ID field indicates that this value has never been
// looked up and cached, a value of 1 indicates this value contains the cached
// `OverrideState` that was looked up via `base::FeatureList`, and any other
// value indicate that this cached value is only valid for a particular
// ScopedFeatureList instance.
//
// Packing these values into a uint32_t makes it so that atomic operations
// performed on this fields can be lock free.
//
// The override state stored in this field is only used if the current
// `FeatureList::caching_context_` field is equal to the lower 16 bits of the
// packed cached value. Otherwise, the override state is looked up in the
// feature list and the cache is updated.
mutable std::atomic<uint32_t> cached_value = 0;
}; };
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// DCHECKs have been built-in, and are configurable at run-time to be fatal, or // DCHECKs have been built-in, and are configurable at run-time to be fatal, or
// not, via a DcheckIsFatal feature. We define the Feature here since it is // not, via a DcheckIsFatal feature. We define the Feature here since it is
// checked in FeatureList::SetInstance(). See https://crbug.com/596231. // checked in FeatureList::SetInstance(). See https://crbug.com/596231.
extern BASE_EXPORT const Feature kDCheckIsFatalFeature; extern BASE_EXPORT const Feature kDCheckIsFatalFeature;
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// The FeatureList class is used to determine whether a given feature is on or // The FeatureList class is used to determine whether a given feature is on or
// off. It provides an authoritative answer, taking into account command-line // off. It provides an authoritative answer, taking into account command-line
@ -258,12 +303,16 @@ class BASE_EXPORT FeatureList {
// accepted by InitializeFromCommandLine()) corresponding to features that // accepted by InitializeFromCommandLine()) corresponding to features that
// have been overridden - either through command-line or via FieldTrials. For // have been overridden - either through command-line or via FieldTrials. For
// those features that have an associated FieldTrial, the output entry will be // those features that have an associated FieldTrial, the output entry will be
// of the format "FeatureName<TrialName", where "TrialName" is the name of the // of the format "FeatureName<TrialName" (|include_group_name|=false) or
// FieldTrial. Features that have overrides with OVERRIDE_USE_DEFAULT will be // "FeatureName<TrialName.GroupName" (if |include_group_name|=true), where
// added to |enable_overrides| with a '*' character prefix. Must be called // "TrialName" is the name of the FieldTrial and "GroupName" is the group
// only after the instance has been initialized and registered. // name of the FieldTrial. Features that have overrides with
// OVERRIDE_USE_DEFAULT will be added to |enable_overrides| with a '*'
// character prefix. Must be called only after the instance has been
// initialized and registered.
void GetFeatureOverrides(std::string* enable_overrides, void GetFeatureOverrides(std::string* enable_overrides,
std::string* disable_overrides) const; std::string* disable_overrides,
bool include_group_names = false) const;
// Like GetFeatureOverrides(), but only returns overrides that were specified // Like GetFeatureOverrides(), but only returns overrides that were specified
// explicitly on the command-line, omitting the ones from field trials. // explicitly on the command-line, omitting the ones from field trials.
@ -308,6 +357,19 @@ class BASE_EXPORT FeatureList {
static std::vector<base::StringPiece> SplitFeatureListString( static std::vector<base::StringPiece> SplitFeatureListString(
base::StringPiece input); base::StringPiece input);
// Checks and parses the |enable_feature| (e.g.
// FeatureName<Study.Group:Param1/value1/) obtained by applying
// SplitFeatureListString() to the |enable_features| flag, and sets
// |feature_name| to be the feature's name, |study_name| and |group_name| to
// be the field trial name and its group name if the field trial is specified
// or field trial parameters are given, |params| to be the field trial
// parameters if exists.
static bool ParseEnableFeatureString(StringPiece enable_feature,
std::string* feature_name,
std::string* study_name,
std::string* group_name,
std::string* params);
// Initializes and sets an instance of FeatureList with feature overrides via // Initializes and sets an instance of FeatureList with feature overrides via
// command-line flags |enable_features| and |disable_features| if one has not // command-line flags |enable_features| and |disable_features| if one has not
// already been set from command-line flags. Returns true if an instance did // already been set from command-line flags. Returns true if an instance did
@ -351,6 +413,8 @@ class BASE_EXPORT FeatureList {
// Has no effect if DCHECKs are not enabled. // Has no effect if DCHECKs are not enabled.
static void ForbidUseForCurrentModule(); static void ForbidUseForCurrentModule();
void SetCachingContextForTesting(uint16_t caching_context);
private: private:
FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity); FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
FRIEND_TEST_ALL_PREFIXES(FeatureListTest, FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
@ -441,7 +505,8 @@ class BASE_EXPORT FeatureList {
// function's comments for more details. // function's comments for more details.
void GetFeatureOverridesImpl(std::string* enable_overrides, void GetFeatureOverridesImpl(std::string* enable_overrides,
std::string* disable_overrides, std::string* disable_overrides,
bool command_line_only) const; bool command_line_only,
bool include_group_name = false) const;
// Verifies that there's only a single definition of a Feature struct for a // Verifies that there's only a single definition of a Feature struct for a
// given feature name. Keeps track of the first seen Feature struct for each // given feature name. Keeps track of the first seen Feature struct for each
@ -475,6 +540,11 @@ class BASE_EXPORT FeatureList {
// Whether this object has been initialized from command line. // Whether this object has been initialized from command line.
bool initialized_from_command_line_ = false; bool initialized_from_command_line_ = false;
// Used when querying `base::Feature` state to determine if the cached value
// in the `Feature` object is populated and valid. See the comment on
// `base::Feature::cached_value` for more details.
uint16_t caching_context_ = 1;
}; };
} // namespace base } // namespace base

View File

@ -4,15 +4,6 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "build/build_config.h"
// file_path.h is a widely included header and its size has significant impact
// on build time. Try not to raise this limit unless necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 400000
#endif
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>

View File

@ -1,49 +0,0 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/files/file_path_watcher.h"
#include "base/files/file_path.h"
#include "base/notreached.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace base {
namespace {
class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
public:
FilePathWatcherImpl() = default;
FilePathWatcherImpl(const FilePathWatcherImpl&) = delete;
FilePathWatcherImpl& operator=(const FilePathWatcherImpl&) = delete;
~FilePathWatcherImpl() override = default;
// FilePathWatcher::PlatformDelegate:
bool Watch(const FilePath& path,
Type type,
const FilePathWatcher::Callback& callback) override;
void Cancel() override;
};
bool FilePathWatcherImpl::Watch(const FilePath& path,
Type type,
const FilePathWatcher::Callback& callback) {
DCHECK(!callback.is_null());
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
void FilePathWatcherImpl::Cancel() {
set_cancelled();
}
} // namespace
FilePathWatcher::FilePathWatcher() {
sequence_checker_.DetachFromSequence();
impl_ = std::make_unique<FilePathWatcherImpl>();
}
} // namespace base

View File

@ -673,7 +673,7 @@ bool FilePathWatcherImpl::UpdateRecursiveWatches(
? recursive_paths_by_watch_[fired_watch] ? recursive_paths_by_watch_[fired_watch]
: target_; : target_;
auto start_it = recursive_watches_by_path_.lower_bound(changed_dir); auto start_it = recursive_watches_by_path_.upper_bound(changed_dir);
auto end_it = start_it; auto end_it = start_it;
for (; end_it != recursive_watches_by_path_.end(); ++end_it) { for (; end_it != recursive_watches_by_path_.end(); ++end_it) {
const FilePath& cur_path = end_it->first; const FilePath& cur_path = end_it->first;

View File

@ -15,11 +15,11 @@ namespace base {
// this constants. // this constants.
constexpr TimeDelta kAudioSchedulingPeriod = Milliseconds(10); constexpr TimeDelta kAudioSchedulingPeriod = Milliseconds(10);
// Reserve 10% or one CPU core for audio threads. // Reserve 30% of one CPU core for audio threads.
// TODO(crbug.com/1174811): A different value may need to be used for WebAudio // TODO(crbug.com/1174811): A different value may need to be used for WebAudio
// threads (see media::FuchsiaAudioOutputDevice). A higher capacity may need to // threads (see media::FuchsiaAudioOutputDevice). A higher capacity may need to
// be allocated in that case. // be allocated in that case.
constexpr float kAudioSchedulingCapacity = 0.1; constexpr float kAudioSchedulingCapacity = 0.3;
// Scheduling interval to use for display threads. // Scheduling interval to use for display threads.
// TODO(crbug.com/1224707): Add scheduling period to Thread::Options and remove // TODO(crbug.com/1224707): Add scheduling period to Thread::Options and remove

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// TODO(crbug.com/1227712): Migrate syntax and remove this.
library base.testfidl; library base.testfidl;
@discoverable @discoverable

View File

@ -0,0 +1,102 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FUNCTIONAL_FUNCTION_REF_H_
#define BASE_FUNCTIONAL_FUNCTION_REF_H_
#include <type_traits>
#include <utility>
#include "base/bind_internal.h"
#include "third_party/abseil-cpp/absl/base/attributes.h"
#include "third_party/abseil-cpp/absl/functional/function_ref.h"
namespace base {
template <typename Signature>
class FunctionRef;
// A non-owning reference to any invocable object (e.g. function pointer, method
// pointer, functor, lambda, et cetera) suitable for use as a type-erased
// argument to ForEach-style functions or other visitor patterns that:
//
// - do not need to copy or take ownership of the argument
// - synchronously call the invocable that was passed as an argument
//
// `base::FunctionRef` makes no heap allocations: it is trivially copyable and
// should be passed by value.
//
// `base::FunctionRef` has no null/empty state: a `base::FunctionRef` is always
// valid to invoke.
//
// The usual lifetime precautions for other non-owning references types (e.g.
// `base::StringPiece`, `base::span`) also apply to `base::FunctionRef`.
// `base::FunctionRef` should typically be used as an argument; returning a
// `base::FunctionRef` or storing a `base::FunctionRef` as a field is dangerous
// and likely to result in lifetime bugs.
//
// `base::RepeatingCallback` and `base::BindRepeating()` is another common way
// to represent type-erased invocable objects. In contrast, it requires a heap
// allocation and is not trivially copyable. It should be used when there are
// ownership requirements (e.g. partial application of arguments to a function
// stored for asynchronous execution).
//
// Note: this class is very similar to `absl::FunctionRef<R(Args...)>`, but
// disallows implicit conversions between function types, e.g. functors that
// return non-void values may bind to `absl::FunctionRef<void(...)>`:
//
// ```
// void F(absl::FunctionRef<void()>);
// ...
// F([] { return 42; });
// ```
//
// This compiles and silently discards the return value, but with the base
// version, the equivalent snippet:
//
// ```
// void F(base::FunctionRef<void()>);
// ...
// F([] { return 42;});
// ```
//
// will not compile at all.
template <typename R, typename... Args>
class FunctionRef<R(Args...)> {
public:
// `ABSL_ATTRIBUTE_LIFETIME_BOUND` is important since `FunctionRef` retains
// only a reference to `functor`, `functor` must outlive `this`.
template <typename Functor,
typename = std::enable_if_t<std::is_same_v<
R(Args...),
typename internal::MakeFunctorTraits<Functor>::RunType>>>
// NOLINTNEXTLINE(google-explicit-constructor)
FunctionRef(const Functor& functor ABSL_ATTRIBUTE_LIFETIME_BOUND)
: wrapped_func_ref_(functor) {}
// Null FunctionRefs are not allowed.
FunctionRef() = delete;
FunctionRef(const FunctionRef&) = default;
// Reduce the likelihood of lifetime bugs by disallowing assignment.
FunctionRef& operator=(const FunctionRef&) = delete;
R operator()(Args... args) const {
return wrapped_func_ref_(std::forward<Args>(args)...);
}
absl::FunctionRef<R(Args...)> ToAbsl() const { return wrapped_func_ref_; }
// In Chrome, converting to `absl::FunctionRef` should be explicitly done
// through `ToAbsl()`.
template <typename Signature>
operator absl::FunctionRef<Signature>() = delete;
private:
absl::FunctionRef<R(Args...)> wrapped_func_ref_;
};
} // namespace base
#endif // BASE_FUNCTIONAL_FUNCTION_REF_H_

View File

@ -82,7 +82,7 @@ struct MD5CE {
DCHECK_EQ(m % 64, 0u); DCHECK_EQ(m % 64, 0u);
if (i < n) { if (i < n) {
// Emit the message itself... // Emit the message itself...
return data[i]; return static_cast<uint8_t>(data[i]);
} else if (i == n) { } else if (i == n) {
// ...followed by the end of message marker. // ...followed by the end of message marker.
return 0x80; return 0x80;

View File

@ -17,29 +17,109 @@ namespace device_util {
// The returned string is the string returned by sysctlbyname() with name // The returned string is the string returned by sysctlbyname() with name
// "hw.machine". Possible (known) values include: // "hw.machine". Possible (known) values include:
// //
// iPhone1,1 -> iPhone 1G // iPhone7,1 -> iPhone 6 Plus
// iPhone1,2 -> iPhone 3G // iPhone7,2 -> iPhone 6
// iPhone2,1 -> iPhone 3GS // iPhone8,1 -> iPhone 6s
// iPhone3,1 -> iPhone 4/AT&T // iPhone8,2 -> iPhone 6s Plus
// iPhone3,2 -> iPhone 4/Other Carrier? // iPhone8,4 -> iPhone SE (GSM)
// iPhone3,3 -> iPhone 4/Other Carrier? // iPhone9,1 -> iPhone 7
// iPhone4,1 -> iPhone 4S // iPhone9,2 -> iPhone 7 Plus
// iPhone9,3 -> iPhone 7
// iPhone9,4 -> iPhone 7 Plus
// iPhone10,1 -> iPhone 8
// iPhone10,2 -> iPhone 8 Plus
// iPhone10,3 -> iPhone X Global
// iPhone10,4 -> iPhone 8
// iPhone10,5 -> iPhone 8 Plus
// iPhone10,6 -> iPhone X GSM
// iPhone11,2 -> iPhone XS
// iPhone11,4 -> iPhone XS Max
// iPhone11,6 -> iPhone XS Max Global
// iPhone11,8 -> iPhone XR
// iPhone12,1 -> iPhone 11
// iPhone12,3 -> iPhone 11 Pro
// iPhone12,5 -> iPhone 11 Pro Max
// iPhone12,8 -> iPhone SE 2nd Gen
// iPhone13,1 -> iPhone 12 Mini
// iPhone13,2 -> iPhone 12
// iPhone13,3 -> iPhone 12 Pro
// iPhone13,4 -> iPhone 12 Pro Max
// iPhone14,2 -> iPhone 13 Pro
// iPhone14,3 -> iPhone 13 Pro Max
// iPhone14,4 -> iPhone 13 Mini
// iPhone14,5 -> iPhone 13
// iPhone14,6 -> iPhone SE 3rd Gen
// iPhone14,7 -> iPhone 14
// iPhone14,8 -> iPhone 14 Plus
// iPhone15,2 -> iPhone 14 Pro
// iPhone15,3 -> iPhone 14 Pro Max
// //
// iPod1,1 -> iPod touch 1G // iPad3,4 -> 4th Gen iPad
// iPod2,1 -> iPod touch 2G // iPad3,5 -> 4th Gen iPad GSM+LTE
// iPod2,2 -> ? // iPad3,6 -> 4th Gen iPad CDMA+LTE
// iPod3,1 -> iPod touch 3G // iPad4,1 -> iPad Air (WiFi)
// iPod4,1 -> iPod touch 4G // iPad4,2 -> iPad Air (GSM+CDMA)
// iPod5,1 -> ? // iPad4,3 -> 1st Gen iPad Air (China)
// // iPad4,4 -> iPad mini Retina (WiFi)
// iPad1,1 -> iPad 1G, WiFi // iPad4,5 -> iPad mini Retina (GSM+CDMA)
// iPad1,? -> iPad 1G, 3G <- needs 3G owner to test // iPad4,6 -> iPad mini Retina (China)
// iPad2,1 -> iPad 2G, WiFi // iPad4,7 -> iPad mini 3 (WiFi)
// iPad4,8 -> iPad mini 3 (GSM+CDMA)
// iPad4,9 -> iPad Mini 3 (China)
// iPad5,1 -> iPad mini 4 (WiFi)
// iPad5,2 -> 4th Gen iPad mini (WiFi+Cellular)
// iPad5,3 -> iPad Air 2 (WiFi)
// iPad5,4 -> iPad Air 2 (Cellular)
// iPad6,3 -> iPad Pro (9.7 inch, WiFi)
// iPad6,4 -> iPad Pro (9.7 inch, WiFi+LTE)
// iPad6,7 -> iPad Pro (12.9 inch, WiFi)
// iPad6,8 -> iPad Pro (12.9 inch, WiFi+LTE)
// iPad6,11 -> iPad (2017)
// iPad6,12 -> iPad (2017)
// iPad7,1 -> iPad Pro 2nd Gen (WiFi)
// iPad7,2 -> iPad Pro 2nd Gen (WiFi+Cellular)
// iPad7,3 -> iPad Pro 10.5-inch 2nd Gen
// iPad7,4 -> iPad Pro 10.5-inch 2nd Gen
// iPad7,5 -> iPad 6th Gen (WiFi)
// iPad7,6 -> iPad 6th Gen (WiFi+Cellular)
// iPad7,11 -> iPad 7th Gen 10.2-inch (WiFi)
// iPad7,12 -> iPad 7th Gen 10.2-inch (WiFi+Cellular)
// iPad8,1 -> iPad Pro 11 inch 3rd Gen (WiFi)
// iPad8,2 -> iPad Pro 11 inch 3rd Gen (1TB, WiFi)
// iPad8,3 -> iPad Pro 11 inch 3rd Gen (WiFi+Cellular)
// iPad8,4 -> iPad Pro 11 inch 3rd Gen (1TB, WiFi+Cellular)
// iPad8,5 -> iPad Pro 12.9 inch 3rd Gen (WiFi)
// iPad8,6 -> iPad Pro 12.9 inch 3rd Gen (1TB, WiFi)
// iPad8,7 -> iPad Pro 12.9 inch 3rd Gen (WiFi+Cellular)
// iPad8,8 -> iPad Pro 12.9 inch 3rd Gen (1TB, WiFi+Cellular)
// iPad8,9 -> iPad Pro 11 inch 4th Gen (WiFi)
// iPad8,10 -> iPad Pro 11 inch 4th Gen (WiFi+Cellular)
// iPad8,11 -> iPad Pro 12.9 inch 4th Gen (WiFi)
// iPad8,12 -> iPad Pro 12.9 inch 4th Gen (WiFi+Cellular)
// iPad11,1 -> iPad mini 5th Gen (WiFi)
// iPad11,2 -> iPad mini 5th Gen
// iPad11,3 -> iPad Air 3rd Gen (WiFi)
// iPad11,4 -> iPad Air 3rd Gen
// iPad11,6 -> iPad 8th Gen (WiFi)
// iPad11,7 -> iPad 8th Gen (WiFi+Cellular)
// iPad12,1 -> iPad 9th Gen (WiFi)
// iPad12,2 -> iPad 9th Gen (WiFi+Cellular)
// iPad14,1 -> iPad mini 6th Gen (WiFi)
// iPad14,2 -> iPad mini 6th Gen (WiFi+Cellular)
// iPad13,1 -> iPad Air 4th Gen (WiFi)
// iPad13,2 -> iPad Air 4th Gen (WiFi+Cellular)
// iPad13,4 -> iPad Pro 11 inch 5th Gen
// iPad13,5 -> iPad Pro 11 inch 5th Gen
// iPad13,6 -> iPad Pro 11 inch 5th Gen
// iPad13,7 -> iPad Pro 11 inch 5th Gen
// iPad13,8 -> iPad Pro 12.9 inch 5th Gen
// iPad13,9 -> iPad Pro 12.9 inch 5th Gen
// iPad13,10 -> iPad Pro 12.9 inch 5th Gen
// iPad13,11 -> iPad Pro 12.9 inch 5th Gen
// iPad13,16 -> iPad Air 5th Gen (WiFi)
// iPad13,17 -> iPad Air 5th Gen (WiFi+Cellular)
// //
// AppleTV2,1 -> AppleTV 2 // AppleTV2,1 -> AppleTV 2
//
// i386 -> Simulator
// x86_64 -> Simulator
std::string GetPlatform(); std::string GetPlatform();
// Returns true if the application is running on a device with 512MB or more // Returns true if the application is running on a device with 512MB or more

View File

@ -58,11 +58,15 @@ namespace ios {
namespace device_util { namespace device_util {
std::string GetPlatform() { std::string GetPlatform() {
#if TARGET_OS_SIMULATOR
return getenv("SIMULATOR_MODEL_IDENTIFIER");
#elif TARGET_OS_IPHONE
std::string platform; std::string platform;
size_t size = 0; size_t size = 0;
sysctlbyname("hw.machine", NULL, &size, NULL, 0); sysctlbyname("hw.machine", NULL, &size, NULL, 0);
sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0); sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0);
return platform; return platform;
#endif
} }
bool RamIsAtLeast512Mb() { bool RamIsAtLeast512Mb() {

View File

@ -58,6 +58,10 @@ BASE_EXPORT bool IsMultipleScenesSupported();
// speed up actual launch time. // speed up actual launch time.
BASE_EXPORT bool IsApplicationPreWarmed(); BASE_EXPORT bool IsApplicationPreWarmed();
// The iPhone 14 Pro and Pro Max introduced a dynamic island. This should only
// be called when working around UIKit bugs.
BASE_EXPORT bool HasDynamicIsland();
} // namespace ios } // namespace ios
} // namespace base } // namespace base

View File

@ -8,6 +8,7 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include <stddef.h> #include <stddef.h>
#import "base/ios/device_util.h"
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
@ -87,5 +88,12 @@ bool IsApplicationPreWarmed() {
return [NSProcessInfo.processInfo.environment objectForKey:@"ActivePrewarm"]; return [NSProcessInfo.processInfo.environment objectForKey:@"ActivePrewarm"];
} }
bool HasDynamicIsland() {
std::string hardware_model = ::ios::device_util::GetPlatform();
static bool is_dynamic_island_model =
(hardware_model == "iPhone15,2" || hardware_model == "iPhone15,3");
return is_dynamic_island_model;
}
} // namespace ios } // namespace ios
} // namespace base } // namespace base

View File

@ -480,7 +480,7 @@ absl::optional<Value> JSONParser::ConsumeList() {
return absl::nullopt; return absl::nullopt;
} }
Value::ListStorage list_storage; Value::List list;
Token token = GetNextToken(); Token token = GetNextToken();
while (token != T_ARRAY_END) { while (token != T_ARRAY_END) {
@ -490,7 +490,7 @@ absl::optional<Value> JSONParser::ConsumeList() {
return absl::nullopt; return absl::nullopt;
} }
list_storage.push_back(std::move(*item)); list.Append(std::move(*item));
token = GetNextToken(); token = GetNextToken();
if (token == T_LIST_SEPARATOR) { if (token == T_LIST_SEPARATOR) {
@ -508,7 +508,7 @@ absl::optional<Value> JSONParser::ConsumeList() {
ConsumeChar(); // Closing ']'. ConsumeChar(); // Closing ']'.
return Value(std::move(list_storage)); return Value(std::move(list));
} }
absl::optional<Value> JSONParser::ConsumeString() { absl::optional<Value> JSONParser::ConsumeString() {

View File

@ -4,25 +4,16 @@
#include "base/location.h" #include "base/location.h"
#include "build/build_config.h"
// location.h is a widely included header and its size can significantly impact
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 390000
#endif
#if defined(COMPILER_MSVC)
#include <intrin.h>
#endif
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/trace_event/base_tracing.h" #include "base/trace_event/base_tracing.h"
#include "build/build_config.h" #include "build/build_config.h"
#if defined(COMPILER_MSVC)
#include <intrin.h>
#endif
namespace base { namespace base {
namespace { namespace {

View File

@ -3,15 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/logging.h" #include "base/logging.h"
#include <atomic>
#include <memory>
// logging.h is a widely included header and its size has significant impact on
// build time. Try not to raise this limit unless absolutely necessary. See
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
#ifndef NACL_TC_REV
#pragma clang max_tokens_here 470000
#endif // NACL_TC_REV
#ifdef BASE_CHECK_H_ #ifdef BASE_CHECK_H_
#error "logging.h should not include check.h" #error "logging.h should not include check.h"
@ -20,14 +11,13 @@
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <atomic>
#include <memory>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "base/base_export.h" #include "base/base_export.h"
#include "base/debug/crash_logging.h" #include "base/debug/crash_logging.h"
#if defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL)
#include "base/debug/leak_annotations.h"
#endif // defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL)
#include "base/immediate_crash.h" #include "base/immediate_crash.h"
#include "base/pending_task.h" #include "base/pending_task.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
@ -35,6 +25,15 @@
#include "base/trace_event/base_tracing.h" #include "base/trace_event/base_tracing.h"
#include "build/build_config.h" #include "build/build_config.h"
#if !BUILDFLAG(IS_NACL)
#include "base/auto_reset.h"
#include "base/debug/crash_logging.h"
#endif // !BUILDFLAG(IS_NACL)
#if defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL)
#include "base/debug/leak_annotations.h"
#endif // defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL)
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
#include <io.h> #include <io.h>
#include <windows.h> #include <windows.h>
@ -462,14 +461,53 @@ void WriteToFd(int fd, const char* data, size_t length) {
} }
} }
void SetLogFatalCrashKey(LogMessage* log_message) {
#if !BUILDFLAG(IS_NACL)
// In case of an out-of-memory condition, this code could be reentered when
// constructing and storing the key. Using a static is not thread-safe, but if
// multiple threads are in the process of a fatal crash at the same time, this
// should work.
static bool guarded = false;
if (guarded)
return;
base::AutoReset<bool> guard(&guarded, true);
static auto* const crash_key = base::debug::AllocateCrashKeyString(
"LOG_FATAL", base::debug::CrashKeySize::Size1024);
base::debug::SetCrashKeyString(crash_key, log_message->BuildCrashString());
#endif // !BUILDFLAG(IS_NACL)
}
std::string BuildCrashString(const char* file,
int line,
const char* message_without_prefix) {
// Only log last path component.
if (file) {
const char* slash = strrchr(file,
#if BUILDFLAG(IS_WIN)
'\\'
#else
'/'
#endif // BUILDFLAG(IS_WIN)
);
if (slash) {
file = slash + 1;
}
}
return base::StringPrintf("%s:%d: %s", file, line, message_without_prefix);
}
} // namespace } // namespace
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// In DCHECK-enabled Chrome builds, allow the meaning of LOGGING_DCHECK to be // In DCHECK-enabled Chrome builds, allow the meaning of LOGGING_DCHECK to be
// determined at run-time. We default it to INFO, to avoid it triggering // determined at run-time. We default it to INFO, to avoid it triggering
// crashes before the run-time has explicitly chosen the behaviour. // crashes before the run-time has explicitly chosen the behaviour.
BASE_EXPORT logging::LogSeverity LOGGING_DCHECK = LOGGING_INFO; BASE_EXPORT logging::LogSeverity LOGGING_DCHECK = LOGGING_INFO;
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have // This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have
// an object of the correct type on the LHS of the unused part of the ternary // an object of the correct type on the LHS of the unused part of the ternary
@ -691,6 +729,9 @@ LogMessage::~LogMessage() {
TRACE_LOG_MESSAGE( TRACE_LOG_MESSAGE(
file_, base::StringPiece(str_newline).substr(message_start_), line_); file_, base::StringPiece(str_newline).substr(message_start_), line_);
if (severity_ == LOGGING_FATAL)
SetLogFatalCrashKey(this);
// Give any log message handler first dibs on the message. // Give any log message handler first dibs on the message.
if (g_log_message_handler && if (g_log_message_handler &&
g_log_message_handler(severity_, file_, line_, message_start_, g_log_message_handler(severity_, file_, line_, message_start_,
@ -913,21 +954,8 @@ LogMessage::~LogMessage() {
} }
std::string LogMessage::BuildCrashString() const { std::string LogMessage::BuildCrashString() const {
return BuildCrashString(file(), line(), str().c_str() + message_start_); return logging::BuildCrashString(file(), line(),
} str().c_str() + message_start_);
std::string LogMessage::BuildCrashString(const char* file,
int line,
const char* message_without_prefix) {
// Only log last path component.
if (file) {
const char* slash = strrchr(file, '/');
if (slash) {
file = slash + 1;
}
}
return base::StringPrintf("%s:%d: %s", file, line, message_without_prefix);
} }
// writes the common header info to the stream // writes the common header info to the stream

View File

@ -615,11 +615,11 @@ BASE_EXPORT extern std::ostream* g_swallow_stream;
// Definitions for DCHECK et al. // Definitions for DCHECK et al.
#if defined(DCHECK_IS_CONFIGURABLE) #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
BASE_EXPORT extern LogSeverity LOGGING_DCHECK; BASE_EXPORT extern LogSeverity LOGGING_DCHECK;
#else #else
constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL; constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL;
#endif // defined(DCHECK_IS_CONFIGURABLE) #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
// Redefine the standard assert to use our nice log files // Redefine the standard assert to use our nice log files
#undef assert #undef assert
@ -653,9 +653,6 @@ class BASE_EXPORT LogMessage {
// Gets file:line: message in a format suitable for crash reporting. // Gets file:line: message in a format suitable for crash reporting.
std::string BuildCrashString() const; std::string BuildCrashString() const;
static std::string BuildCrashString(const char* file,
int line,
const char* message_without_prefix);
private: private:
void Init(const char* file, int line); void Init(const char* file, int line);

View File

@ -28,8 +28,6 @@
extern "C" { extern "C" {
CFTypeID SecKeyGetTypeID(); CFTypeID SecKeyGetTypeID();
#if !BUILDFLAG(IS_IOS) #if !BUILDFLAG(IS_IOS)
CFTypeID SecACLGetTypeID();
CFTypeID SecTrustedApplicationGetTypeID();
// The NSFont/CTFont toll-free bridging is broken before 10.15. // The NSFont/CTFont toll-free bridging is broken before 10.15.
// http://www.openradar.me/15341349 rdar://15341349 // http://www.openradar.me/15341349 rdar://15341349
// //
@ -408,12 +406,10 @@ CFCastStrict<CTFontRef>(const CFTypeRef& cf_val) {
#endif #endif
#if !BUILDFLAG(IS_IOS) #if !BUILDFLAG(IS_IOS)
CF_CAST_DEFN(SecACL)
CF_CAST_DEFN(SecAccessControl) CF_CAST_DEFN(SecAccessControl)
CF_CAST_DEFN(SecCertificate) CF_CAST_DEFN(SecCertificate)
CF_CAST_DEFN(SecKey) CF_CAST_DEFN(SecKey)
CF_CAST_DEFN(SecPolicy) CF_CAST_DEFN(SecPolicy)
CF_CAST_DEFN(SecTrustedApplication)
#endif #endif
#undef CF_CAST_DEFN #undef CF_CAST_DEFN

View File

@ -36,6 +36,7 @@
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
#include "base/allocator/partition_allocator/partition_tag.h" #include "base/allocator/partition_allocator/partition_tag.h"
#include "base/allocator/partition_allocator/partition_tag_types.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "base/check_op.h" #include "base/check_op.h"
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) #endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
@ -160,12 +161,7 @@ struct MTECheckedPtrImplPartitionAllocSupport {
// Disambiguation: UntagPtr removes the hardware MTE tag, whereas this class // Disambiguation: UntagPtr removes the hardware MTE tag, whereas this class
// is responsible for handling the software MTE tag. // is responsible for handling the software MTE tag.
auto addr = partition_alloc::UntagPtr(ptr); auto addr = partition_alloc::UntagPtr(ptr);
// MTECheckedPtr algorithms work only when memory is return partition_alloc::IsManagedByPartitionAlloc(addr);
// allocated by PartitionAlloc, from normal buckets pool.
//
// TODO(crbug.com/1307514): Allow direct-map buckets.
return partition_alloc::IsManagedByPartitionAlloc(addr) &&
partition_alloc::internal::IsManagedByNormalBuckets(addr);
} }
// Returns pointer to the tag that protects are pointed by |addr|. // Returns pointer to the tag that protects are pointed by |addr|.
@ -202,6 +198,7 @@ struct MTECheckedPtrImpl {
static_assert(sizeof(partition_alloc::PartitionTag) * 8 <= kTagBits, ""); static_assert(sizeof(partition_alloc::PartitionTag) * 8 <= kTagBits, "");
uintptr_t tag = *(static_cast<volatile partition_alloc::PartitionTag*>( uintptr_t tag = *(static_cast<volatile partition_alloc::PartitionTag*>(
PartitionAllocSupport::TagPointer(addr))); PartitionAllocSupport::TagPointer(addr)));
DCHECK(tag);
tag <<= kValidAddressBits; tag <<= kValidAddressBits;
addr |= tag; addr |= tag;
@ -458,14 +455,43 @@ struct BackupRefPtrImpl {
typename Z, typename Z,
typename = std::enable_if_t<offset_type<Z>, void>> typename = std::enable_if_t<offset_type<Z>, void>>
static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) {
#if DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS) #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
// First check if the new address lands within the same allocation
// (end-of-allocation address is ok too). It has a non-trivial cost, but
// it's cheaper and more secure than the previous implementation that
// rewrapped the pointer (wrapped the new pointer and unwrapped the old
// one).
uintptr_t address = partition_alloc::UntagPtr(wrapped_ptr); uintptr_t address = partition_alloc::UntagPtr(wrapped_ptr);
if (IsSupportedAndNotNull(address)) if (IsSupportedAndNotNull(address))
CHECK(IsValidDelta(address, delta_elems * static_cast<Z>(sizeof(T)))); CHECK(IsValidDelta(address, delta_elems * static_cast<Z>(sizeof(T))));
return wrapped_ptr + delta_elems;
#else
// In the "before allocation" mode, on 32-bit, we can run into a problem
// that the end-of-allocation address could fall out of "GigaCage", if this
// is the last slot of the super page, thus pointing to the guard page. This
// mean the ref-count won't be decreased when the pointer is released
// (leak).
//
// We could possibly solve it in a few different ways:
// - Add the trailing guard page to "GigaCage", but we'd have to think very
// hard if this doesn't create another hole.
// - Add an address adjustment to "GigaCage" check, similar as the one in
// PartitionAllocGetSlotStartInBRPPool(), but that seems fragile, not to
// mention adding an extra instruction to an inlined hot path.
// - Let the leak happen, since it should a very rare condition.
// - Go back to the previous solution of rewrapping the pointer, but that
// had an issue of losing protection in case the pointer ever gets shifter
// before the end of allocation.
//
// We decided to cross that bridge once we get there... if we ever get
// there. Currently there are no plans to switch back to the "before
// allocation" mode.
//
// This problem doesn't exist in the "previous slot" mode, or any mode that
// involves putting extras after the allocation, because the
// end-of-allocation address belongs to the same slot.
static_assert(false);
#endif #endif
T* new_wrapped_ptr = WrapRawPtr(wrapped_ptr + delta_elems);
ReleaseWrappedPtr(wrapped_ptr);
return new_wrapped_ptr;
} }
// Returns a copy of a wrapped pointer, without making an assertion on whether // Returns a copy of a wrapped pointer, without making an assertion on whether
@ -685,6 +711,16 @@ struct IsSupportedType<content::responsiveness::Calculator> {
static constexpr bool value = false; static constexpr bool value = false;
}; };
// IsRawPtrCountingImpl<T>::value answers whether T is a specialization of
// RawPtrCountingImplWrapperForTest, to know whether Impl is for testing
// purposes.
template <typename T>
struct IsRawPtrCountingImpl : std::false_type {};
template <typename T>
struct IsRawPtrCountingImpl<internal::RawPtrCountingImplWrapperForTest<T>>
: std::true_type {};
#if __OBJC__ #if __OBJC__
// raw_ptr<T> is not compatible with pointers to Objective-C classes for a // raw_ptr<T> is not compatible with pointers to Objective-C classes for a
// multitude of reasons. They may fail to compile in many cases, and wouldn't // multitude of reasons. They may fail to compile in many cases, and wouldn't
@ -772,6 +808,11 @@ using DefaultRawPtrImpl = RawPtrBanDanglingIfSupported;
template <typename T, typename Impl = DefaultRawPtrImpl> template <typename T, typename Impl = DefaultRawPtrImpl>
class TRIVIAL_ABI GSL_POINTER raw_ptr { class TRIVIAL_ABI GSL_POINTER raw_ptr {
using DanglingRawPtr = std::conditional_t<
raw_ptr_traits::IsRawPtrCountingImpl<Impl>::value,
raw_ptr<T, internal::RawPtrCountingImplWrapperForTest<RawPtrMayDangle>>,
raw_ptr<T, RawPtrMayDangle>>;
public: public:
static_assert(raw_ptr_traits::IsSupportedType<T>::value, static_assert(raw_ptr_traits::IsSupportedType<T>::value,
"raw_ptr<T> doesn't work with this kind of pointee type T"); "raw_ptr<T> doesn't work with this kind of pointee type T");
@ -788,15 +829,23 @@ class TRIVIAL_ABI GSL_POINTER raw_ptr {
p.wrapped_ptr_ = nullptr; p.wrapped_ptr_ = nullptr;
} }
ALWAYS_INLINE raw_ptr& operator=(const raw_ptr& p) { ALWAYS_INLINE raw_ptr& operator=(const raw_ptr& p) noexcept {
// Duplicate before releasing, in case the pointer is assigned to itself. // Duplicate before releasing, in case the pointer is assigned to itself.
//
// Unlike the move version of this operator, don't add |this != &p| branch,
// for performance reasons. Even though Duplicate() is not cheap, we
// practically never assign a raw_ptr<T> to itself. We suspect that a
// cumulative cost of a conditional branch, even if always correctly
// predicted, would exceed that.
T* new_ptr = Impl::Duplicate(p.wrapped_ptr_); T* new_ptr = Impl::Duplicate(p.wrapped_ptr_);
Impl::ReleaseWrappedPtr(wrapped_ptr_); Impl::ReleaseWrappedPtr(wrapped_ptr_);
wrapped_ptr_ = new_ptr; wrapped_ptr_ = new_ptr;
return *this; return *this;
} }
ALWAYS_INLINE raw_ptr& operator=(raw_ptr&& p) { ALWAYS_INLINE raw_ptr& operator=(raw_ptr&& p) noexcept {
// Unlike the the copy version of this operator, this branch is necessaty
// for correctness.
if (LIKELY(this != &p)) { if (LIKELY(this != &p)) {
Impl::ReleaseWrappedPtr(wrapped_ptr_); Impl::ReleaseWrappedPtr(wrapped_ptr_);
wrapped_ptr_ = p.wrapped_ptr_; wrapped_ptr_ = p.wrapped_ptr_;
@ -830,7 +879,7 @@ class TRIVIAL_ABI GSL_POINTER raw_ptr {
ALWAYS_INLINE raw_ptr& operator=(const raw_ptr&) noexcept = default; ALWAYS_INLINE raw_ptr& operator=(const raw_ptr&) noexcept = default;
ALWAYS_INLINE raw_ptr& operator=(raw_ptr&&) noexcept = default; ALWAYS_INLINE raw_ptr& operator=(raw_ptr&&) noexcept = default;
ALWAYS_INLINE ~raw_ptr() = default; ALWAYS_INLINE ~raw_ptr() noexcept = default;
#endif // BUILDFLAG(USE_BACKUP_REF_PTR) #endif // BUILDFLAG(USE_BACKUP_REF_PTR)
@ -977,26 +1026,43 @@ class TRIVIAL_ABI GSL_POINTER raw_ptr {
// during the free operation, which will lead to taking the slower path that // during the free operation, which will lead to taking the slower path that
// involves quarantine. // involves quarantine.
ALWAYS_INLINE void ClearAndDelete() noexcept { ALWAYS_INLINE void ClearAndDelete() noexcept {
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) delete GetForExtractionAndReset();
// We cannot directly `delete` a wrapped pointer, since the tag bits
// atop will lead PA totally astray.
T* ptr = Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_);
#else
T* ptr = wrapped_ptr_;
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
operator=(nullptr);
delete ptr;
} }
ALWAYS_INLINE void ClearAndDeleteArray() noexcept { ALWAYS_INLINE void ClearAndDeleteArray() noexcept {
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) delete[] GetForExtractionAndReset();
// We cannot directly `delete` a wrapped pointer, since the tag bits }
// atop will lead PA totally astray.
T* ptr = Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_); // Clear the underlying pointer and return another raw_ptr instance
#else // that is allowed to dangle.
T* ptr = wrapped_ptr_; // This can be useful in cases such as:
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS) // ```
operator=(nullptr); // ptr.ExtractAsDangling()->SelfDestroy();
delete[] ptr; // ```
// ```
// c_style_api_do_something_and_destroy(ptr.ExtractAsDangling());
// ```
// NOTE, avoid using this method as it indicates an error-prone memory
// ownership pattern. If possible, use smart pointers like std::unique_ptr<>
// instead of raw_ptr<>.
// If you have to use it, avoid saving the return value in a long-lived
// variable (or worse, a field)! It's meant to be used as a temporary, to be
// passed into a cleanup & freeing function, and destructed at the end of the
// statement.
ALWAYS_INLINE DanglingRawPtr ExtractAsDangling() noexcept {
if constexpr (std::is_same_v<
typename std::remove_reference<decltype(*this)>::type,
DanglingRawPtr>) {
DanglingRawPtr res(std::move(*this));
// Not all implementation clear the source pointer on move, so do it
// here just in case. Should be cheap.
operator=(nullptr);
return res;
} else {
T* ptr = GetForExtraction();
DanglingRawPtr res(ptr);
operator=(nullptr);
return res;
}
} }
// Comparison operators between raw_ptr and raw_ptr<U>/U*/std::nullptr_t. // Comparison operators between raw_ptr and raw_ptr<U>/U*/std::nullptr_t.
@ -1131,6 +1197,12 @@ class TRIVIAL_ABI GSL_POINTER raw_ptr {
return Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_); return Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_);
} }
ALWAYS_INLINE T* GetForExtractionAndReset() {
T* ptr = GetForExtraction();
operator=(nullptr);
return ptr;
}
T* wrapped_ptr_; T* wrapped_ptr_;
template <typename U, typename V> template <typename U, typename V>
@ -1215,7 +1287,7 @@ using DisableDanglingPtrDetection = base::RawPtrMayDangle;
// See `docs/dangling_ptr.md` // See `docs/dangling_ptr.md`
// Annotates known dangling raw_ptr. Those haven't been triaged yet. All the // Annotates known dangling raw_ptr. Those haven't been triaged yet. All the
// occurrences are meant to be removed. See https://cbug.com/1291138. // occurrences are meant to be removed. See https://crbug.com/1291138.
using DanglingUntriaged = DisableDanglingPtrDetection; using DanglingUntriaged = DisableDanglingPtrDetection;
// The following template parameters are only meaningful when `raw_ptr` // The following template parameters are only meaningful when `raw_ptr`

View File

@ -1,7 +1,7 @@
# raw_ptr&lt;T&gt; (aka MiraclePtr, aka BackupRefPtr) # raw_ptr&lt;T&gt; (aka MiraclePtr, aka BackupRefPtr)
`raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety over `raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety over
over raw pointers. It behaves just like a raw pointer on platforms where raw pointers. It behaves just like a raw pointer on platforms where
USE_BACKUP_REF_PTR is off, and almost like one when it's on. The main USE_BACKUP_REF_PTR is off, and almost like one when it's on. The main
difference is that when USE_BACKUP_REF_PTR is enabled, it's zero-initialized and difference is that when USE_BACKUP_REF_PTR is enabled, it's zero-initialized and
cleared on destruction and move. (You should continue to explicitly initialize cleared on destruction and move. (You should continue to explicitly initialize
@ -50,7 +50,7 @@ exclusions via:
- Code that cannot depend on `//base` - Code that cannot depend on `//base`
- Code in `//ppapi` - Code in `//ppapi`
- `RAW_PTR_EXCLUSION` C++ attribute to exclude individual fields. Examples: - `RAW_PTR_EXCLUSION` C++ attribute to exclude individual fields. Examples:
- Cases where `raw_ptr<T>` won't compile (e.g. cases coverd in - Cases where `raw_ptr<T>` won't compile (e.g. cases covered in
[the "Unsupported cases leading to compile errors" section](#Unsupported-cases-leading-to-compile-errors)). [the "Unsupported cases leading to compile errors" section](#Unsupported-cases-leading-to-compile-errors)).
Make sure to also look at Make sure to also look at
[the "Recoverable compile-time problems" section](#Recoverable-compile_time-problems). [the "Recoverable compile-time problems" section](#Recoverable-compile_time-problems).

View File

@ -20,6 +20,14 @@ This is the brief version. Googlers can search internally for further
reading. reading.
*** ***
*** aside
MTECheckedPtr is one particular incarnation of `raw_ptr`, and so the
primary documentation is kept here in `//base/memory/`. However, the
implementation is woven deeply into PartitionAlloc, and inevitably
some dirty PA-internal details may bubble up here when discussing
how MTECheckedPtr works.
***
MTECheckedPtr is a Chromium-specific implementation of ARM's MTECheckedPtr is a Chromium-specific implementation of ARM's
[MTE concept][arm-mte]. When MTECheckedPtr is enabled, [MTE concept][arm-mte]. When MTECheckedPtr is enabled,
@ -84,4 +92,22 @@ When MTECheckedPtr *is* enabled (not the default for anybody),
both of the above degrade the `raw_ptr<T, D>` into the no-op version both of the above degrade the `raw_ptr<T, D>` into the no-op version
of `raw_ptr`. of `raw_ptr`.
## Appendix: PA-Internal Tag Locations
[The top-level PartitionAlloc documentation][pa-readme]
mentions the space in which
MTECheckedPtr's tags reside - in the space labeled "Bitmaps(?)" in the
super page diagram, before the first usable slot span. This diagram
only applies to *normal* buckets and not to *direct map* buckets.
While direct map super pages also cordon off the first partition page
and offer access to the core metadata within, reservations are always
permissible immediately after, and there are no bitmaps (whether
from *Scan or MTECheckedPtr) following that first partition page.
In implementing MTECheckedPtr support for direct maps, we decided
not to add this extra headroom for bitmaps; instead, the tag is
placed directly in `SubsequentPageMetadata`, colocated with the core
metadata in the first partition page.
[arm-mte]: https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/enhancing-memory-safety [arm-mte]: https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/enhancing-memory-safety
[pa-readme]: ../allocator/partition_allocator/PartitionAlloc.md#layout-in-memory

View File

@ -5,6 +5,7 @@
#ifndef BASE_MEMORY_RAW_REF_H_ #ifndef BASE_MEMORY_RAW_REF_H_
#define BASE_MEMORY_RAW_REF_H_ #define BASE_MEMORY_RAW_REF_H_
#include <memory>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -67,7 +68,7 @@ class TRIVIAL_ABI GSL_POINTER raw_ref {
std::is_same_v<Impl, internal::AsanBackupRefPtrImpl>; std::is_same_v<Impl, internal::AsanBackupRefPtrImpl>;
public: public:
ALWAYS_INLINE explicit raw_ref(T& p) noexcept : inner_(&p) {} ALWAYS_INLINE explicit raw_ref(T& p) noexcept : inner_(std::addressof(p)) {}
ALWAYS_INLINE raw_ref& operator=(T& p) noexcept { ALWAYS_INLINE raw_ref& operator=(T& p) noexcept {
inner_.operator=(&p); inner_.operator=(&p);
@ -274,6 +275,29 @@ class TRIVIAL_ABI GSL_POINTER raw_ref {
template <class T> template <class T>
raw_ref(T) -> raw_ref<T>; raw_ref(T) -> raw_ref<T>;
// Template helpers for working with raw_ref<T>.
template <typename T>
struct IsRawRef : std::false_type {};
template <typename T, typename I>
struct IsRawRef<raw_ref<T, I>> : std::true_type {};
template <typename T>
inline constexpr bool IsRawRefV = IsRawRef<T>::value;
template <typename T>
struct RemoveRawRef {
using type = T;
};
template <typename T, typename I>
struct RemoveRawRef<raw_ref<T, I>> {
using type = T;
};
template <typename T>
using RemoveRawRefT = typename RemoveRawRef<T>::type;
} // namespace base } // namespace base
using base::raw_ref; using base::raw_ref;
@ -292,40 +316,12 @@ struct less<raw_ref<T, Impl>> {
return lhs < rhs; return lhs < rhs;
} }
bool operator()(const raw_ref<const T, Impl>& lhs, bool operator()(T& lhs, const raw_ref<T, Impl>& rhs) const {
const raw_ref<const T, Impl>& rhs) const {
Impl::IncrementLessCountForTest(); Impl::IncrementLessCountForTest();
return lhs < rhs; return lhs < rhs;
} }
bool operator()(const raw_ref<T, Impl>& lhs, bool operator()(const raw_ref<T, Impl>& lhs, T& rhs) const {
const raw_ref<const T, Impl>& rhs) const {
Impl::IncrementLessCountForTest();
return lhs < rhs;
}
bool operator()(const raw_ref<const T, Impl>& lhs,
const raw_ref<T, Impl>& rhs) const {
Impl::IncrementLessCountForTest();
return lhs < rhs;
}
bool operator()(const T& lhs, const raw_ref<const T, Impl>& rhs) const {
Impl::IncrementLessCountForTest();
return lhs < rhs;
}
bool operator()(const T& lhs, const raw_ref<T, Impl>& rhs) const {
Impl::IncrementLessCountForTest();
return lhs < rhs;
}
bool operator()(const raw_ref<const T, Impl>& lhs, const T& rhs) const {
Impl::IncrementLessCountForTest();
return lhs < rhs;
}
bool operator()(const raw_ref<T, Impl>& lhs, const T& rhs) const {
Impl::IncrementLessCountForTest(); Impl::IncrementLessCountForTest();
return lhs < rhs; return lhs < rhs;
} }

View File

@ -8,6 +8,7 @@
#include <type_traits> #include <type_traits>
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/template_util.h" #include "base/template_util.h"
// It is dangerous to post a task with a T* argument where T is a subtype of // It is dangerous to post a task with a T* argument where T is a subtype of
@ -36,8 +37,13 @@ struct IsRefCountedType<T,
// pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) type. // pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) type.
template <typename T> template <typename T>
struct NeedsScopedRefptrButGetsRawPtr struct NeedsScopedRefptrButGetsRawPtr
: std::conjunction<base::IsPointer<T>, : std::disjunction<
IsRefCountedType<base::RemovePointerT<T>>> { // TODO(danakj): Should ban native references and
// std::reference_wrapper here too.
std::conjunction<base::IsRawRef<T>,
IsRefCountedType<base::RemoveRawRefT<T>>>,
std::conjunction<base::IsPointer<T>,
IsRefCountedType<base::RemovePointerT<T>>>> {
static_assert(!std::is_reference<T>::value, static_assert(!std::is_reference<T>::value,
"NeedsScopedRefptrButGetsRawPtr requires non-reference type."); "NeedsScopedRefptrButGetsRawPtr requires non-reference type.");
}; };

View File

@ -237,6 +237,14 @@ void MessagePumpEpoll::OnEpollEvent(const epoll_event& e) {
// `entry` during the loop below. This copy is inexpensive in practice // `entry` during the loop below. This copy is inexpensive in practice
// because the size of this vector is expected to be very small (<= 2). // because the size of this vector is expected to be very small (<= 2).
auto interests = entry.interests; auto interests = entry.interests;
// Any of these interests' event handlers may destroy any of the others'
// controllers. Start all of them watching for destruction before we actually
// dispatch any events.
for (const auto& interest : interests.container()) {
interest->WatchForControllerDestruction();
}
for (const auto& interest : interests.container()) { for (const auto& interest : interests.container()) {
if (!interest->active()) { if (!interest->active()) {
continue; continue;
@ -260,7 +268,13 @@ void MessagePumpEpoll::OnEpollEvent(const epoll_event& e) {
UpdateEpollEvent(entry); UpdateEpollEvent(entry);
} }
HandleEvent(entry.fd, can_read, can_write, interest->controller()); if (!interest->was_controller_destroyed()) {
HandleEvent(entry.fd, can_read, can_write, interest->controller());
}
}
for (const auto& interest : interests.container()) {
interest->StopWatchingForControllerDestruction();
} }
} }
@ -286,13 +300,17 @@ void MessagePumpEpoll::HandleEvent(int fd,
controller->created_from_location().file_name()); controller->created_from_location().file_name());
if (can_read && can_write) { if (can_read && can_write) {
bool controller_was_destroyed = false; bool controller_was_destroyed = false;
controller->was_destroyed_ = &controller_was_destroyed; bool* previous_was_destroyed_flag =
std::exchange(controller->was_destroyed_, &controller_was_destroyed);
controller->OnFdWritable(); controller->OnFdWritable();
if (!controller_was_destroyed) { if (!controller_was_destroyed) {
controller->OnFdReadable(); controller->OnFdReadable();
} }
if (!controller_was_destroyed) { if (!controller_was_destroyed) {
controller->was_destroyed_ = nullptr; controller->was_destroyed_ = previous_was_destroyed_flag;
} else if (previous_was_destroyed_flag) {
*previous_was_destroyed_flag = true;
} }
} else if (can_write) { } else if (can_write) {
controller->OnFdWritable(); controller->OnFdWritable();

View File

@ -182,9 +182,10 @@ MessagePumpGlib::MessagePumpGlib()
if (RunningOnMainThread()) { if (RunningOnMainThread()) {
context_ = g_main_context_default(); context_ = g_main_context_default();
} else { } else {
context_ = g_main_context_new(); owned_context_ = std::unique_ptr<GMainContext, GMainContextDeleter>(
g_main_context_new());
context_ = owned_context_.get();
g_main_context_push_thread_default(context_); g_main_context_push_thread_default(context_);
context_owned_ = true;
} }
// Create our wakeup pipe, which is used to flag when work was scheduled. // Create our wakeup pipe, which is used to flag when work was scheduled.
@ -197,25 +198,22 @@ MessagePumpGlib::MessagePumpGlib()
wakeup_gpollfd_->fd = wakeup_pipe_read_; wakeup_gpollfd_->fd = wakeup_pipe_read_;
wakeup_gpollfd_->events = G_IO_IN; wakeup_gpollfd_->events = G_IO_IN;
work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); work_source_ = std::unique_ptr<GSource, GSourceDeleter>(
static_cast<WorkSource*>(work_source_)->pump = this; g_source_new(&WorkSourceFuncs, sizeof(WorkSource)));
g_source_add_poll(work_source_, wakeup_gpollfd_.get()); static_cast<WorkSource*>(work_source_.get())->pump = this;
g_source_set_priority(work_source_, kPriorityWork); g_source_add_poll(work_source_.get(), wakeup_gpollfd_.get());
g_source_set_priority(work_source_.get(), kPriorityWork);
// This is needed to allow Run calls inside Dispatch. // This is needed to allow Run calls inside Dispatch.
g_source_set_can_recurse(work_source_, TRUE); g_source_set_can_recurse(work_source_.get(), TRUE);
g_source_attach(work_source_, context_); g_source_attach(work_source_.get(), context_);
} }
MessagePumpGlib::~MessagePumpGlib() { MessagePumpGlib::~MessagePumpGlib() {
g_source_destroy(work_source_); work_source_.reset();
g_source_unref(work_source_);
close(wakeup_pipe_read_); close(wakeup_pipe_read_);
close(wakeup_pipe_write_); close(wakeup_pipe_write_);
context_ = nullptr;
if (context_owned_) { owned_context_.reset();
g_main_context_pop_thread_default(context_);
g_main_context_unref(context_);
}
} }
MessagePumpGlib::FdWatchController::FdWatchController(const Location& location) MessagePumpGlib::FdWatchController::FdWatchController(const Location& location)

View File

@ -5,6 +5,7 @@
#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_ #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_ #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
#include <glib.h>
#include <memory> #include <memory>
#include "base/base_export.h" #include "base/base_export.h"
@ -14,10 +15,6 @@
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "base/time/time.h" #include "base/time/time.h"
typedef struct _GMainContext GMainContext;
typedef struct _GPollFD GPollFD;
typedef struct _GSource GSource;
namespace base { namespace base {
// This class implements a base MessagePump needed for TYPE_UI MessageLoops on // This class implements a base MessagePump needed for TYPE_UI MessageLoops on
@ -110,6 +107,22 @@ class BASE_EXPORT MessagePumpGlib : public MessagePump,
void HandleFdWatchDispatch(FdWatchController* controller); void HandleFdWatchDispatch(FdWatchController* controller);
private: private:
struct GMainContextDeleter {
inline void operator()(GMainContext* context) const {
if (context) {
g_main_context_pop_thread_default(context);
g_main_context_unref(context);
}
}
};
struct GSourceDeleter {
inline void operator()(GSource* source) const {
if (source) {
g_source_destroy(source);
g_source_unref(source);
}
}
};
bool ShouldQuit() const; bool ShouldQuit() const;
// We may make recursive calls to Run, so we save state that needs to be // We may make recursive calls to Run, so we save state that needs to be
@ -118,15 +131,15 @@ class BASE_EXPORT MessagePumpGlib : public MessagePump,
raw_ptr<RunState> state_; raw_ptr<RunState> state_;
std::unique_ptr<GMainContext, GMainContextDeleter> owned_context_;
// This is a GLib structure that we can add event sources to. On the main // This is a GLib structure that we can add event sources to. On the main
// thread, we use the default GLib context, which is the one to which all GTK // thread, we use the default GLib context, which is the one to which all GTK
// events are dispatched. // events are dispatched.
raw_ptr<GMainContext, DanglingUntriaged> context_ = nullptr; raw_ptr<GMainContext> context_ = nullptr;
bool context_owned_ = false;
// The work source. It is shared by all calls to Run and destroyed when // The work source. It is shared by all calls to Run and destroyed when
// the message pump is destroyed. // the message pump is destroyed.
raw_ptr<GSource, DanglingUntriaged> work_source_; std::unique_ptr<GSource, GSourceDeleter> work_source_;
// We use a wakeup pipe to make sure we'll get out of the glib polling phase // We use a wakeup pipe to make sure we'll get out of the glib polling phase
// when another thread has scheduled us to do some work. There is a glib // when another thread has scheduled us to do some work. There is a glib

View File

@ -137,7 +137,7 @@ void MessagePumpLibevent::FdWatchController::OnFdWritable() {
watcher_->OnFileCanWriteWithoutBlocking(epoll_interest_->params().fd); watcher_->OnFileCanWriteWithoutBlocking(epoll_interest_->params().fd);
} }
MessagePumpLibevent::MessagePumpLibevent() : event_base_(event_base_new()) { MessagePumpLibevent::MessagePumpLibevent() {
#if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL) #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
if (g_use_epoll) { if (g_use_epoll) {
epoll_pump_ = std::make_unique<MessagePumpEpoll>(); epoll_pump_ = std::make_unique<MessagePumpEpoll>();
@ -154,8 +154,7 @@ MessagePumpLibevent::MessagePumpLibevent() : event_base_(event_base_new()) {
#if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL) #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
MessagePumpLibevent::MessagePumpLibevent(decltype(kUseEpoll)) MessagePumpLibevent::MessagePumpLibevent(decltype(kUseEpoll))
: epoll_pump_(std::make_unique<MessagePumpEpoll>()), : epoll_pump_(std::make_unique<MessagePumpEpoll>()) {
event_base_(event_base_new()) {
epoll_pump_ = std::make_unique<MessagePumpEpoll>(); epoll_pump_ = std::make_unique<MessagePumpEpoll>();
} }
#endif #endif
@ -170,8 +169,8 @@ MessagePumpLibevent::~MessagePumpLibevent() {
DCHECK(event_base_); DCHECK(event_base_);
if (using_libevent) { if (using_libevent) {
DCHECK(wakeup_event_); DCHECK(wakeup_event_);
event_del(wakeup_event_); event_del(wakeup_event_.get());
delete wakeup_event_; wakeup_event_.reset();
if (wakeup_pipe_in_ >= 0) { if (wakeup_pipe_in_ >= 0) {
if (IGNORE_EINTR(close(wakeup_pipe_in_)) < 0) if (IGNORE_EINTR(close(wakeup_pipe_in_)) < 0)
DPLOG(ERROR) << "close"; DPLOG(ERROR) << "close";
@ -181,7 +180,7 @@ MessagePumpLibevent::~MessagePumpLibevent() {
DPLOG(ERROR) << "close"; DPLOG(ERROR) << "close";
} }
} }
event_base_free(event_base_); event_base_.reset();
} }
// Must be called early in process startup, but after FeatureList // Must be called early in process startup, but after FeatureList
@ -251,7 +250,7 @@ bool MessagePumpLibevent::WatchFileDescriptor(int fd,
event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller); event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
// Tell libevent which message pump this socket will belong to when we add it. // Tell libevent which message pump this socket will belong to when we add it.
if (event_base_set(event_base_, evt.get())) { if (event_base_set(event_base_.get(), evt.get())) {
DPLOG(ERROR) << "event_base_set(fd=" << EVENT_FD(evt.get()) << ")"; DPLOG(ERROR) << "event_base_set(fd=" << EVENT_FD(evt.get()) << ")";
return false; return false;
} }
@ -313,7 +312,7 @@ void MessagePumpLibevent::Run(Delegate* delegate) {
// OnLibeventNotification() did enter a nested loop from here, it // OnLibeventNotification() did enter a nested loop from here, it
// wouldn't be labeled as such in tracing by "ThreadController active". // wouldn't be labeled as such in tracing by "ThreadController active".
// Contact gab@/scheduler-dev@ if a problematic trace emerges. // Contact gab@/scheduler-dev@ if a problematic trace emerges.
event_base_loop(event_base_, EVLOOP_NONBLOCK); event_base_loop(event_base_.get(), EVLOOP_NONBLOCK);
bool attempt_more_work = immediate_work_available || processed_io_events_; bool attempt_more_work = immediate_work_available || processed_io_events_;
processed_io_events_ = false; processed_io_events_ = false;
@ -343,8 +342,8 @@ void MessagePumpLibevent::Run(Delegate* delegate) {
struct timeval poll_tv; struct timeval poll_tv;
poll_tv.tv_sec = static_cast<time_t>(delay.InSeconds()); poll_tv.tv_sec = static_cast<time_t>(delay.InSeconds());
poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond; poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
event_set(timer_event.get(), -1, 0, timer_callback, event_base_); event_set(timer_event.get(), -1, 0, timer_callback, event_base_.get());
event_base_set(event_base_, timer_event.get()); event_base_set(event_base_.get(), timer_event.get());
event_add(timer_event.get(), &poll_tv); event_add(timer_event.get(), &poll_tv);
did_set_timer = true; did_set_timer = true;
@ -354,7 +353,7 @@ void MessagePumpLibevent::Run(Delegate* delegate) {
// is conditionally interrupted to look for more work if we are aware of a // is conditionally interrupted to look for more work if we are aware of a
// delayed task that will need servicing. // delayed task that will need servicing.
delegate->BeforeWait(); delegate->BeforeWait();
event_base_loop(event_base_, EVLOOP_ONCE); event_base_loop(event_base_.get(), EVLOOP_ONCE);
// We previously setup a timer to break out the event loop to look for more // We previously setup a timer to break out the event loop to look for more
// work. Now that we're here delete the event. // work. Now that we're here delete the event.
@ -413,12 +412,12 @@ bool MessagePumpLibevent::Init() {
wakeup_pipe_out_ = fds[0]; wakeup_pipe_out_ = fds[0];
wakeup_pipe_in_ = fds[1]; wakeup_pipe_in_ = fds[1];
wakeup_event_ = new event; wakeup_event_ = std::make_unique<event>();
event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST, event_set(wakeup_event_.get(), wakeup_pipe_out_, EV_READ | EV_PERSIST,
OnWakeup, this); OnWakeup, this);
event_base_set(event_base_, wakeup_event_); event_base_set(event_base_.get(), wakeup_event_.get());
if (event_add(wakeup_event_, nullptr)) if (event_add(wakeup_event_.get(), nullptr))
return false; return false;
return true; return true;
} }
@ -479,7 +478,7 @@ void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
DCHECK_EQ(nread, 1); DCHECK_EQ(nread, 1);
that->processed_io_events_ = true; that->processed_io_events_ = true;
// Tell libevent to break out of inner loop. // Tell libevent to break out of inner loop.
event_base_loopbreak(that->event_base_); event_base_loopbreak(that->event_base_.get());
} }
MessagePumpLibevent::EpollInterest::EpollInterest( MessagePumpLibevent::EpollInterest::EpollInterest(

View File

@ -16,11 +16,11 @@
#include "base/message_loop/message_pump_buildflags.h" #include "base/message_loop/message_pump_buildflags.h"
#include "base/message_loop/watchable_io_message_pump_posix.h" #include "base/message_loop/watchable_io_message_pump_posix.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "third_party/libevent/event.h"
// Declare structs we need from libevent.h rather than including it // Declare structs we need from libevent.h rather than including it
struct event_base; struct event_base;
struct event; struct event;
namespace base { namespace base {
class MessagePumpEpoll; class MessagePumpEpoll;
@ -72,6 +72,22 @@ class BASE_EXPORT MessagePumpLibevent : public MessagePump,
bool active() const { return active_; } bool active() const { return active_; }
void set_active(bool active) { active_ = active; } void set_active(bool active) { active_ = active; }
// Only meaningful between WatchForControllerDestruction() and
// StopWatchingForControllerDestruction().
bool was_controller_destroyed() const { return was_controller_destroyed_; }
void WatchForControllerDestruction() {
DCHECK(!controller_->was_destroyed_);
controller_->was_destroyed_ = &was_controller_destroyed_;
}
void StopWatchingForControllerDestruction() {
if (!was_controller_destroyed_) {
DCHECK_EQ(controller_->was_destroyed_, &was_controller_destroyed_);
controller_->was_destroyed_ = nullptr;
}
}
private: private:
friend class RefCounted<EpollInterest>; friend class RefCounted<EpollInterest>;
~EpollInterest(); ~EpollInterest();
@ -79,6 +95,7 @@ class BASE_EXPORT MessagePumpLibevent : public MessagePump,
FdWatchController* const controller_; FdWatchController* const controller_;
const EpollInterestParams params_; const EpollInterestParams params_;
bool active_ = true; bool active_ = true;
bool was_controller_destroyed_ = false;
}; };
// Note that this class is used as the FdWatchController for both // Note that this class is used as the FdWatchController for both
@ -220,16 +237,22 @@ class BASE_EXPORT MessagePumpLibevent : public MessagePump,
// This flag is set if libevent has processed I/O events. // This flag is set if libevent has processed I/O events.
bool processed_io_events_ = false; bool processed_io_events_ = false;
struct EventBaseFree {
inline void operator()(event_base* e) const {
if (e)
event_base_free(e);
}
};
// Libevent dispatcher. Watches all sockets registered with it, and sends // Libevent dispatcher. Watches all sockets registered with it, and sends
// readiness callbacks when a socket is ready for I/O. // readiness callbacks when a socket is ready for I/O.
const raw_ptr<event_base, DanglingUntriaged> event_base_; std::unique_ptr<event_base, EventBaseFree> event_base_{event_base_new()};
// ... write end; ScheduleWork() writes a single byte to it // ... write end; ScheduleWork() writes a single byte to it
int wakeup_pipe_in_ = -1; int wakeup_pipe_in_ = -1;
// ... read end; OnWakeup reads it and then breaks Run() out of its sleep // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
int wakeup_pipe_out_ = -1; int wakeup_pipe_out_ = -1;
// ... libevent wrapper for read end // ... libevent wrapper for read end
raw_ptr<event, DanglingUntriaged> wakeup_event_ = nullptr; std::unique_ptr<event> wakeup_event_;
ThreadChecker watch_file_descriptor_caller_checker_; ThreadChecker watch_file_descriptor_caller_checker_;
}; };

View File

@ -514,9 +514,13 @@ void MessagePumpCFRunLoopBase::RunIdleWork() {
// objects if the app is not currently handling a UI event to ensure they're // objects if the app is not currently handling a UI event to ensure they're
// released promptly even in the absence of UI events. // released promptly even in the absence of UI events.
MessagePumpScopedAutoreleasePool autorelease_pool(this); MessagePumpScopedAutoreleasePool autorelease_pool(this);
// Call DoIdleWork once, and if something was done, arrange to come back here // Pop the current work item scope as it captures any native work happening
// again as long as the loop is still running. // *between* the last DoWork() and this DoIdleWork()
PopWorkItemScope();
bool did_work = delegate_->DoIdleWork(); bool did_work = delegate_->DoIdleWork();
// As in DoWork(), push a new scope to cover any native work that could
// possibly happen between now and BeforeWait().
PushWorkItemScope();
if (did_work) if (did_work)
CFRunLoopSourceSignal(idle_work_source_); CFRunLoopSourceSignal(idle_work_source_);
} }
@ -551,6 +555,8 @@ void MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
void MessagePumpCFRunLoopBase::BeforeWait() { void MessagePumpCFRunLoopBase::BeforeWait() {
// Current work item tracking needs to go away since execution will stop. // Current work item tracking needs to go away since execution will stop.
// Matches the PushWorkItemScope() in AfterWaitObserver() (with an arbitrary
// amount of matching Pop/Push in between when running work items).
PopWorkItemScope(); PopWorkItemScope();
if (!delegate_) { if (!delegate_) {
@ -604,7 +610,8 @@ void MessagePumpCFRunLoopBase::AfterWaitObserver(CFRunLoopObserverRef observer,
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
base::mac::CallWithEHFrame(^{ base::mac::CallWithEHFrame(^{
// Emerging from sleep, any work happening after this (outside of a // Emerging from sleep, any work happening after this (outside of a
// RunWork()) should be considered native work. // RunWork()) should be considered native work. Matching PopWorkItemScope()
// is in BeforeWait().
self->PushWorkItemScope(); self->PushWorkItemScope();
}); });
} }

Some files were not shown because too many files have changed in this diff Show More