From c185b8d246d9dc112acb60a170b745e6f14a0bbb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sat, 25 Nov 2023 13:30:50 +0900 Subject: [PATCH] v8,tools: expose necessary V8 defines PR-URL: https://github.com/nodejs/node/pull/50820 Reviewed-By: Jiawen Geng Reviewed-By: James M Snell --- common.gypi | 60 +++++++++++++--- configure.py | 1 + tools/generate_config_gypi.py | 118 ++++++++++++++++++++++++-------- tools/v8_gypfiles/features.gypi | 37 +++++++--- unofficial.gni | 9 +-- 5 files changed, 176 insertions(+), 49 deletions(-) diff --git a/common.gypi b/common.gypi index e1074d04ad8a17..28522c9fbf83b4 100644 --- a/common.gypi +++ b/common.gypi @@ -75,8 +75,16 @@ 'v8_win64_unwinding_info': 1, - # TODO(refack): make v8-perfetto happen + # Variables controlling external defines exposed in public headers. + 'v8_enable_conservative_stack_scanning%': 0, + 'v8_enable_direct_local%': 0, + 'v8_enable_map_packing%': 0, + 'v8_enable_pointer_compression_shared_cage%': 0, + 'v8_enable_sandbox%': 0, + 'v8_enable_v8_checks%': 0, + 'v8_enable_zone_compression%': 0, 'v8_use_perfetto': 0, + 'tsan%': 0, ##### end V8 defaults ##### @@ -134,7 +142,7 @@ }], ], }, - 'defines': [ 'DEBUG', '_DEBUG', 'V8_ENABLE_CHECKS' ], + 'defines': [ 'DEBUG', '_DEBUG' ], 'cflags': [ '-g', '-O0' ], 'conditions': [ ['OS in "aix os400"', { @@ -257,11 +265,8 @@ } }, - # Defines these mostly for node-gyp to pickup, and warn addon authors of - # imminent V8 deprecations, also to sync how dependencies are configured. + # Defines these mostly for node-gyp to pickup. 'defines': [ - 'V8_DEPRECATION_WARNINGS', - 'V8_IMMINENT_DEPRECATION_WARNINGS', '_GLIBCXX_USE_CXX11_ABI=1', ], @@ -369,15 +374,50 @@ }], ], }], + # The defines bellow must include all things from the external_v8_defines + # list in v8/BUILD.gn. + ['v8_enable_v8_checks == 1', { + 'defines': ['V8_ENABLE_CHECKS'], + }], ['v8_enable_pointer_compression == 1', { - 'defines': [ - 'V8_COMPRESS_POINTERS', - 'V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE', - ], + 'defines': ['V8_COMPRESS_POINTERS'], + }], + ['v8_enable_pointer_compression_shared_cage == 1', { + 'defines': ['V8_COMPRESS_POINTERS_IN_SHARED_CAGE'], + }], + ['v8_enable_pointer_compression == 1 and v8_enable_pointer_compression_shared_cage != 1', { + 'defines': ['V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE'], }], ['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', { 'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'], }], + ['v8_enable_zone_compression == 1', { + 'defines': ['V8_COMPRESS_ZONES',], + }], + ['v8_enable_sandbox == 1', { + 'defines': ['V8_ENABLE_SANDBOX',], + }], + ['v8_deprecation_warnings == 1', { + 'defines': ['V8_DEPRECATION_WARNINGS',], + }], + ['v8_imminent_deprecation_warnings == 1', { + 'defines': ['V8_IMMINENT_DEPRECATION_WARNINGS',], + }], + ['v8_use_perfetto == 1', { + 'defines': ['V8_USE_PERFETTO',], + }], + ['v8_enable_map_packing == 1', { + 'defines': ['V8_MAP_PACKING',], + }], + ['tsan == 1', { + 'defines': ['V8_IS_TSAN',], + }], + ['v8_enable_conservative_stack_scanning == 1', { + 'defines': ['V8_ENABLE_CONSERVATIVE_STACK_SCANNING',], + }], + ['v8_enable_direct_local == 1', { + 'defines': ['V8_ENABLE_DIRECT_LOCAL',], + }], ['OS == "win"', { 'defines': [ 'WIN32', diff --git a/configure.py b/configure.py index ff08312b680146..84b016cd853080 100755 --- a/configure.py +++ b/configure.py @@ -1505,6 +1505,7 @@ def configure_v8(o): o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0 o['variables']['v8_enable_shared_ro_heap'] = 0 if options.enable_pointer_compression or options.disable_shared_ro_heap else 1 o['variables']['v8_enable_extensible_ro_snapshot'] = 0 + o['variables']['v8_enable_v8_checks'] = 1 if options.debug else 0 o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0 o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform) o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8) diff --git a/tools/generate_config_gypi.py b/tools/generate_config_gypi.py index 26cc5f04201fec..948a740529ec34 100755 --- a/tools/generate_config_gypi.py +++ b/tools/generate_config_gypi.py @@ -7,69 +7,133 @@ # This script reads the configurations of GN and outputs a config.gypi file that # will be used to populate process.config.variables. +import argparse import re import os import subprocess import sys -root_dir = os.path.dirname(os.path.dirname(__file__)) -sys.path.append(os.path.join(root_dir, 'node', 'tools')) -import getmoduleversion +sys.path.append(os.path.dirname(__file__)) import getnapibuildversion +# The defines bellow must include all things from the external_v8_defines list +# in v8/BUILD.gn. +# TODO(zcbenz): Import from v8_features.json once this change gets into Node: +# https://chromium-review.googlesource.com/c/v8/v8/+/5040612 +V8_FEATURE_DEFINES = { + 'v8_enable_v8_checks': 'V8_ENABLE_CHECKS', + 'v8_enable_pointer_compression': 'V8_COMPRESS_POINTERS', + 'v8_enable_pointer_compression_shared_cage': 'V8_COMPRESS_POINTERS_IN_SHARED_CAGE', + 'v8_enable_31bit_smis_on_64bit_arch': 'V8_31BIT_SMIS_ON_64BIT_ARCH', + 'v8_enable_zone_compression': 'V8_COMPRESS_ZONES', + 'v8_enable_sandbox': 'V8_ENABLE_SANDBOX', + 'v8_deprecation_warnings': 'V8_DEPRECATION_WARNINGS', + 'v8_imminent_deprecation_warnings': 'V8_IMMINENT_DEPRECATION_WARNINGS', + 'v8_use_perfetto': 'V8_USE_PERFETTO', + 'v8_enable_map_packing': 'V8_MAP_PACKING', + 'tsan': 'V8_IS_TSAN', + 'v8_enable_conservative_stack_scanning': 'V8_ENABLE_CONSERVATIVE_STACK_SCANNING', + 'v8_enable_direct_local': 'V8_ENABLE_DIRECT_LOCAL', +} + +# Regex used for parsing results of "gn args". GN_RE = re.compile(r'(\w+)\s+=\s+(.*?)$', re.MULTILINE) +if sys.platform == 'win32': + GN = 'gn.exe' +else: + GN = 'gn' + +def bool_to_number(v): + return 1 if v else 0 + def bool_string_to_number(v): - return 1 if v == 'true' else 0 + return bool_to_number(v == 'true') + +def get_gn_config(out_dir): + # Read args from GN configurations. + gn_args = subprocess.check_output( + [GN, 'args', '--list', '--short', '-C', out_dir]) + config = dict(re.findall(GN_RE, gn_args.decode())) + # Get napi_build_version from Node, which is not part of GN args. + config['napi_build_version'] = getnapibuildversion.get_napi_version() + return config + +def get_v8_config(out_dir, node_gn_path): + # For args that have default values in V8's GN configurations, we can not rely + # on the values printed by "gn args", because most of them would be empty + # strings, and the actual value would depend on the logics in v8/BUILD.gn. + # So we print out the defines and deduce the feature from them instead. + node_defines = subprocess.check_output( + [GN, 'desc', '-C', out_dir, node_gn_path + ":libnode", 'defines']).decode().split('\n') + v8_config = {} + for feature, define in V8_FEATURE_DEFINES.items(): + v8_config[feature] = bool_to_number(define in node_defines) + return v8_config -def translate_config(config): - return { +def translate_config(out_dir, config, v8_config): + config_gypi = { 'target_defaults': { 'default_configuration': 'Debug' if config['is_debug'] == 'true' else 'Release', }, 'variables': { 'asan': bool_string_to_number(config['is_asan']), + 'enable_lto': config['use_thin_lto'], + 'is_debug': bool_string_to_number(config['is_debug']), 'llvm_version': 13, 'napi_build_version': config['napi_build_version'], 'node_builtin_shareable_builtins': eval(config['node_builtin_shareable_builtins']), 'node_module_version': int(config['node_module_version']), - 'node_shared': bool_string_to_number(config['is_component_build']), 'node_use_openssl': config['node_use_openssl'], 'node_use_node_code_cache': config['node_use_node_code_cache'], 'node_use_node_snapshot': config['node_use_node_snapshot'], - 'v8_enable_31bit_smis_on_64bit_arch': - bool_string_to_number(config['v8_enable_31bit_smis_on_64bit_arch']), - 'v8_enable_pointer_compression': - bool_string_to_number(config['v8_enable_pointer_compression']), 'v8_enable_i18n_support': bool_string_to_number(config['v8_enable_i18n_support']), 'v8_enable_inspector': # this is actually a node misnomer bool_string_to_number(config['node_enable_inspector']), 'shlib_suffix': 'dylib' if sys.platform == 'darwin' else 'so', + 'tsan': bool_string_to_number(config['is_tsan']), + # TODO(zcbenz): Shared components are not supported in GN config yet. + 'node_shared': 'false', + 'node_shared_brotli': 'false', + 'node_shared_cares': 'false', + 'node_shared_http_parser': 'false', + 'node_shared_libuv': 'false', + 'node_shared_nghttp2': 'false', + 'node_shared_nghttp3': 'false', + 'node_shared_ngtcp2': 'false', + 'node_shared_openssl': 'false', + 'node_shared_zlib': 'false', } } + config_gypi['variables'].update(v8_config) + return config_gypi -def main(gn_out_dir, output_file, depfile): - # Get GN config and parse into a dictionary. - if sys.platform == 'win32': - gn = 'gn.exe' - else: - gn = 'gn' - gnconfig = subprocess.check_output( - [gn, 'args', '--list', '--short', '-C', gn_out_dir]) - config = dict(re.findall(GN_RE, gnconfig.decode('utf-8'))) - config['node_module_version'] = getmoduleversion.get_version() - config['napi_build_version'] = getnapibuildversion.get_napi_version() +def main(): + parser = argparse.ArgumentParser( + description='Generate config.gypi file from GN configurations') + parser.add_argument('target', help='path to generated config.gypi file') + parser.add_argument('--out-dir', help='path to the output directory', + default='out/Release') + parser.add_argument('--node-gn-path', help='path of the node target in GN', + default='//node') + parser.add_argument('--dep-file', help='path to an optional dep file', + default=None) + args, unknown_args = parser.parse_known_args() + + config = get_gn_config(args.out_dir) + v8_config = get_v8_config(args.out_dir, args.node_gn_path) # Write output. - with open(output_file, 'w') as f: - f.write(repr(translate_config(config))) + with open(args.target, 'w') as f: + f.write(repr(translate_config(args.out_dir, config, v8_config))) # Write depfile. Force regenerating config.gypi when GN configs change. - with open(depfile, 'w') as f: - f.write('%s: %s '%(output_file, 'build.ninja')) + if args.dep_file: + with open(args.dep_file, 'w') as f: + f.write('%s: %s '%(args.target, 'build.ninja')) if __name__ == '__main__': - main(sys.argv[1], sys.argv[2], sys.argv[3]) + main() diff --git a/tools/v8_gypfiles/features.gypi b/tools/v8_gypfiles/features.gypi index b5738243363182..be1dfe407a290d 100644 --- a/tools/v8_gypfiles/features.gypi +++ b/tools/v8_gypfiles/features.gypi @@ -155,6 +155,7 @@ # Enable pointer compression (sets -dV8_COMPRESS_POINTERS). 'v8_enable_pointer_compression%': 0, + 'v8_enable_pointer_compression_shared_cage%': 0, 'v8_enable_31bit_smis_on_64bit_arch%': 0, # Sets -dV8_SHORT_BUILTIN_CALLS @@ -197,6 +198,15 @@ # currently implemented. 'v8_use_perfetto%': 0, + # Enable map packing & unpacking (sets -dV8_MAP_PACKING). + 'v8_enable_map_packing%': 0, + + # Scan the call stack conservatively during garbage collection. + 'v8_enable_conservative_stack_scanning%': 0, + + # Use direct pointers in local handles. + 'v8_enable_direct_local%': 0, + # Controls the threshold for on-heap/off-heap Typed Arrays. 'v8_typed_array_max_size_in_heap%': 64, @@ -345,10 +355,13 @@ 'defines': ['ENABLE_VTUNE_JIT_INTERFACE',], }], ['v8_enable_pointer_compression==1', { - 'defines': [ - 'V8_COMPRESS_POINTERS', - 'V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE', - ], + 'defines': ['V8_COMPRESS_POINTERS'], + }], + ['v8_enable_pointer_compression_shared_cage==1', { + 'defines': ['V8_COMPRESS_POINTERS_IN_SHARED_CAGE'], + }], + ['v8_enable_pointer_compression==1 and v8_enable_pointer_compression_shared_cage==0', { + 'defines': ['V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE'], }], ['v8_enable_pointer_compression==1 or v8_enable_31bit_smis_on_64bit_arch==1', { 'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH',], @@ -392,13 +405,9 @@ }], ['v8_deprecation_warnings==1', { 'defines': ['V8_DEPRECATION_WARNINGS',], - },{ - 'defines!': ['V8_DEPRECATION_WARNINGS',], }], ['v8_imminent_deprecation_warnings==1', { 'defines': ['V8_IMMINENT_DEPRECATION_WARNINGS',], - },{ - 'defines!': ['V8_IMMINENT_DEPRECATION_WARNINGS',], }], ['v8_enable_i18n_support==1', { 'defines': ['V8_INTL_SUPPORT',], @@ -443,9 +452,21 @@ ['v8_use_perfetto==1', { 'defines': ['V8_USE_PERFETTO',], }], + ['v8_enable_map_packing==1', { + 'defines': ['V8_MAP_PACKING',], + }], ['v8_win64_unwinding_info==1', { 'defines': ['V8_WIN64_UNWINDING_INFO',], }], + ['tsan==1', { + 'defines': ['V8_IS_TSAN',], + }], + ['v8_enable_conservative_stack_scanning==1', { + 'defines': ['V8_ENABLE_CONSERVATIVE_STACK_SCANNING',], + }], + ['v8_enable_direct_local==1', { + 'defines': ['V8_ENABLE_DIRECT_LOCAL',], + }], ['v8_enable_regexp_interpreter_threaded_dispatch==1', { 'defines': ['V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH',], }], diff --git a/unofficial.gni b/unofficial.gni index f13df9503ece1b..ee0a5f3c32dbcc 100644 --- a/unofficial.gni +++ b/unofficial.gni @@ -257,10 +257,11 @@ template("node_gn_build") { script = "tools/generate_config_gypi.py" outputs = [ "$target_gen_dir/config.gypi" ] depfile = "$target_gen_dir/$target_name.d" - script_args = [ "$root_build_dir" ] - script_args += outputs - script_args += [ depfile ] - args = rebase_path(script_args, root_build_dir) + args = rebase_path(outputs, root_build_dir) + [ + "--out-dir", rebase_path(root_build_dir, root_build_dir), + "--dep-file", rebase_path(depfile, root_build_dir), + "--node-gn-path", node_path, + ] } executable("node_js2c") {