v8 150.0.0

Rust bindings to V8
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Chromium presubmit script for base/allocator/partition_allocator.

See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details on the presubmit API built into depot_tools.
"""

PRESUBMIT_VERSION = '2.0.0'

# This is the base path of the partition_alloc directory when stored inside the
# chromium repository. PRESUBMIT.py is executed from chromium.
_PARTITION_ALLOC_BASE_PATH = 'base/allocator/partition_allocator/src/'

# Pattern matching C/C++ source files, for use in allowlist args.
_SOURCE_FILE_PATTERN = r'.*\.(h|hpp|c|cc|cpp)$'

# Similar pattern, matching GN files.
_BUILD_FILE_PATTERN = r'.*\.(gn|gni)$'

# This is adapted from Chromium's PRESUBMIT.py. The differences are:
# - Base path: It is relative to the partition_alloc's source directory instead
#              of chromium.
# - Stricter: A single format is allowed: `PATH_ELEM_FILE_NAME_H_`.
def CheckForIncludeGuards(input_api, output_api):
    """Check that header files have proper include guards"""

    def guard_for_file(file):
        local_path = file.LocalPath()
        if input_api.is_windows:
            local_path = local_path.replace('\\', '/')
        assert local_path.startswith(_PARTITION_ALLOC_BASE_PATH)
        guard = input_api.os_path.normpath(
            local_path[len(_PARTITION_ALLOC_BASE_PATH):])
        guard = guard + '_'
        guard = guard.upper()
        guard = input_api.re.sub(r'[+\\/.-]', '_', guard)
        return guard

    def is_partition_alloc_header_file(f):
        # We only check header files.
        return f.LocalPath().endswith('.h')

    errors = []

    for f in input_api.AffectedSourceFiles(is_partition_alloc_header_file):
        expected_guard = guard_for_file(f)

        # Unlike the Chromium's top-level PRESUBMIT.py, we enforce a stricter
        # rule which accepts only `PATH_ELEM_FILE_NAME_H_` per coding style.
        guard_name_pattern = input_api.re.escape(expected_guard)
        guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
                                             guard_name_pattern + ')')

        guard_name = None
        guard_line_number = None
        seen_guard_end = False
        for line_number, line in enumerate(f.NewContents()):
            if guard_name is None:
                match = guard_pattern.match(line)
                if match:
                    guard_name = match.group(1)
                    guard_line_number = line_number
                continue

            # The line after #ifndef should have a #define of the same name.
            if line_number == guard_line_number + 1:
                expected_line = '#define %s' % guard_name
                if line != expected_line:
                    errors.append(
                        output_api.PresubmitPromptWarning(
                            'Missing "%s" for include guard' % expected_line,
                            ['%s:%d' % (f.LocalPath(), line_number + 1)],
                            'Expected: %r\nGot: %r' % (expected_line, line)))

            if not seen_guard_end and line == '#endif  // %s' % guard_name:
                seen_guard_end = True
                continue

            if seen_guard_end:
                if line.strip() != '':
                    errors.append(
                        output_api.PresubmitPromptWarning(
                            'Include guard %s not covering the whole file' %
                            (guard_name), [f.LocalPath()]))
                    break  # Nothing else to check and enough to warn once.

        if guard_name is None:
            errors.append(
                output_api.PresubmitPromptWarning(
                    'Missing include guard in %s\n'
                    'Recommended name: %s\n' %
                    (f.LocalPath(), expected_guard)))

    return errors

# In .gn and .gni files, check there are no unexpected dependencies on files
# located outside of the partition_alloc repository.
#
# This is important, because partition_alloc has no CQ bots on its own, but only
# through the chromium's CQ.
#
# Only //build_overrides/ is allowed, as it provides embedders, a way to
# overrides the default build settings and forward the dependencies to
# partition_alloc.
def CheckNoExternalImportInGn(input_api, output_api):
    # Match and capture <path> from import("<path>").
    import_re = input_api.re.compile(r'^ *import\("([^"]+)"\)')

    sources = lambda affected_file: input_api.FilterSourceFile(
        affected_file,
        files_to_skip=[],
        files_to_check=[_BUILD_FILE_PATTERN])

    errors = []
    for f in input_api.AffectedSourceFiles(sources):
        for line_number, line in f.ChangedContents():
            match = import_re.search(line)
            if not match:
                continue
            import_path = match.group(1)
            if import_path.startswith('//build_overrides/'):
                continue
            if not import_path.startswith('//'):
                continue;
            errors.append(output_api.PresubmitError(
                '%s:%d\nPartitionAlloc disallow external import: %s' %
                (f.LocalPath(), line_number + 1, import_path)))
    return errors;

def CheckNoCpp23(input_api, output_api):
    """Checks that no C++23 features are used."""

    # 1. RAW_PATTERNS: (Regex Pattern, Feature Name).
    # These are for syntax features or complex matching needs.
    RAW_PATTERNS = [
        # C++23 consteval if statement
        (r'\bif\s+consteval\b', 'if consteval'),

        # C++23 preprocessor directives
        (r'^\s*#\s*elifdef\b', '#elifdef'),
        (r'^\s*#\s*elifndef\b', '#elifndef'),
        (r'^\s*#\s*warning\b', '#warning'),

        # C++23 standard library modules
        (r'\bimport\s+std\b', 'Standard Library Modules'),
        (r'\bimport\s+std\.compat\b', 'Standard Library Modules'),

        # C++23 deducing this
        (r'\bthis\s+auto\b', 'Deducing this (explicit object parameter)'),

        # C++23 size_t literal suffix
        (r'\b\d+(?:u|U)?(?:z|Z)(?:u|U)?\b', 'size_t literal suffix (z/Z)'),

        # C++23 [[assume(...)]] attribute
        (r'\[\[assume\(.*\)\]\]', '[[assume(...)]] attribute'),
    ]

    # 2. LIBRARY_SYMBOLS: Sequence[Symbol Name].
    # Those are only for library symbols added in C++23 accessible from
    # pre-c++23 headers.
    LIBRARY_SYMBOLS = [
        # <utility>, <bit>, <functional> additions
        'std::unreachable',
        'std::to_underlying',
        'std::byteswap',
        'std::forward_like',
        'std::move_only_function',
        'std::invoke_r',

        # <memory> additions:
        'std::start_lifetime_as',
        'std::start_lifetime_as_array',
        'std::out_ptr',
        'std::inout_ptr',
        'std::allocate_at_least',

        # <algorithm> or <ranges> additions:
        'std::ranges::to',
        'std::ranges::fold_left',
        'std::ranges::fold_right',
        'std::ranges::fold_left_first',
        'std::ranges::fold_right_last',
        'std::ranges::fold_left_with_iter',
        'std::ranges::contains',
        'views::zip',
        'views::zip_transform',
        'views::enumerate',
        'views::chunk',
        'views::chunk_by',
        'views::slide',
        'views::stride',
        'views::join_with',
        'views::adjacent',
        'views::adjacent_transform',
        'views::cartesian_product',
        'views::as_rvalue',
        'views::as_const',
        'views::repeat',
    ]

    compiled_checks = []

    for pattern, feature_name in RAW_PATTERNS:
        compiled_checks.append((input_api.re.compile(pattern), feature_name))

    for symbol in LIBRARY_SYMBOLS:
        pattern = r'\b' + input_api.re.escape(symbol) + r'\b'
        description = f'C++23 library symbol: {symbol}'
        compiled_checks.append((input_api.re.compile(pattern), description))

    sources = lambda affected_file: input_api.FilterSourceFile(
        affected_file,
        files_to_skip=[],
        files_to_check=[_SOURCE_FILE_PATTERN])

    errors = []
    for f in input_api.AffectedSourceFiles(sources):
        for line_number, line in enumerate(f.NewContents()):
            # Rudimentary comment stripping to check code only.
            line_no_comment = line.split('//')[0]

            for matcher, error_desc in compiled_checks:
                if matcher.search(line_no_comment):
                    errors.append(
                        output_api.PresubmitError(
                            '%s:%d\nPartitionAlloc disallows C++23 feature: %s'
                            % (f.LocalPath(), line_number + 1, error_desc)))

    return errors

# partition_alloc uses C++20.
def CheckNoCpp23Features(input_api, output_api):
    CPP_23_PATTERNS = (
        r'#include <(expected|flat_map|flat_set|generator|mdspan|print|'
        r'spanstream|stacktrace|stdatomic.h|stdfloat)>',
        r'if !?consteval',
        r'^#elifn?def',
        r'std::byteswap',
        r'#warning',
        r'static.*operator(\(\)|\[\])',
        r'std::from_range',
        r'\[\[assume[^[]*\]\]',
        r'std::move_only_function',
        r'std::unreachable',
        r'std::(in)?out_ptr',
        r'std::start_lifetime_as',
        r'std::ranges::(contains|contains_subrange|starts_with|ends_with|'
        r'find_last|find_last_if|find_last_if_not|iota|shift_left|'
        r'shift_right|fold_left|fold_left_first|fold_right|fold_right_last|'
        r'fold_left_with_iter|fold_left_first_with_iter)',
    )

    sources = lambda affected_file: input_api.FilterSourceFile(
        affected_file,
        # compiler_specific.h may use these headers in guarded ways.
        files_to_skip=[
            r'.*partition_alloc_base/augmentations/compiler_specific\.h'
        ],
        files_to_check=[_SOURCE_FILE_PATTERN])

    errors = []
    for f in input_api.AffectedSourceFiles(sources):
        # for line_number, line in f.ChangedContents():
        for line_number, line in enumerate(f.NewContents()):
            for pattern in CPP_23_PATTERNS:
                match = input_api.re.search(pattern, line)
                if not match:
                    continue
                errors.append(
                    output_api.PresubmitError(
                        '%s:%d\nPartitionAlloc disallows C++23 features: `%s`'
                        % (f.LocalPath(), line_number + 1, match.group(0))))
    return errors

# Check `NDEBUG` is not used inside partition_alloc. We prefer to use the
# buildflags `#if PA_BUILDFLAG(IS_DEBUG)` instead.
def CheckNoNDebug(input_api, output_api):
    sources = lambda affected_file: input_api.FilterSourceFile(
        affected_file,
        files_to_skip=[],
        files_to_check=[_SOURCE_FILE_PATTERN])

    errors = []
    for f in input_api.AffectedSourceFiles(sources):
        for line_number, line in f.ChangedContents():
            if 'NDEBUG' in line:
                errors.append(output_api.PresubmitError('%s:%d\nPartitionAlloc'
                  % (f.LocalPath(), line_number + 1)
                  + 'disallows NDEBUG, use PA_BUILDFLAG(IS_DEBUG) instead'))
    return errors


def CheckUnexpectedPreprocessorDefines(input_api, output_api):
    """
    Checks partition_alloc doesn't depend on chrome's specific definitions.
    """

    # Macros that are allowed to be used with defined(...)
    ALLOWED_DEFINITIONS = {
        # Compiler built-ins
        'ADDRESS_SANITIZER',
        'MEMORY_SANITIZER',
        'THREAD_SANITIZER',
        'WIN32',
        '_CPPUNWIND',
        '_MSC_VER',
        '_WIN32',
        '_WIN64',
        '__AIX',
        '__APPLE__',
        '__ARMEL__',
        '__ARM_FEATURE_BTI_DEFAULT',
        '__ARM_FEATURE_MEMORY_TAGGING',
        '__EXCEPTIONS',
        '__GNUC__',
        '__LP64__',
        '__OBJC__',
        '__arm__',
        '__clang__',
        '__clang_analyzer__',
        '__cpp_constexpr',
        '__cpp_lib_atomic_value_initialization',
        '__cpp_lib_three_way_comparison',
        '__has_attribute',
        '__has_builtin',
        '__has_cpp_attribute',
        '__has_extension',
        '__has_feature',
        '__has_warning',
        '__i386__',
        '__pic__',

        # System/Library macros
        'RTLD_DEEPBIND',
        '_GNU_SOURCE',
        '_POSIX_MONOTONIC_CLOCK',
        '_POSIX_THREAD_CPUTIME',
        '_SC_PAGESIZE',
        'PR_SET_VMA',
        'PR_SET_VMA_ANON_NAME',
        '__BIONIC__',
        '__GLIBC_PREREQ',
        '__GLIBC__',
        '__MALLOC_HOOK_VOLATILE',
        '__NR_mseal',
        '__UCLIBC__',
        '_MIPS_ARCH_LOONGSON',

        # Gtest
        'GTEST_HAS_DEATH_TEST',

        # TODO - The following macros are defined outside of partition_alloc and
        # should be removed/replaced with PA_BUILDFLAG or PA_CONFIG at some
        # point.
        'BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_PARTITION_ALLOC_BASE_CHECK_H_',
        'BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_PARTITION_ALLOC_CHECK_H_',
        'BASE_CHECK_H_',
        'HAS_HW_CAPS',
        'HAVE_BACKTRACE',
        'LINUX_NAME_REGION',
        'MEMORY_TOOL_REPLACES_ALLOCATOR',
        'NDEBUG',
        'NEEDS_HANDLING_OF_HW_CAPABILITIES',
        'OFFICIAL_BUILD',
    }

    target_path_prefix = (
        'base/allocator/partition_allocator/src/partition_alloc/')

    def is_relevant_file(f):
        path = f.LocalPath().replace('\\', '/')
        if path.endswith('/build_config.h'):
            return False
        # Exclude tests
        if any(x in path for x in
               ('unittest', 'perftest', '/test/', '_unittest')):
            return False
        return (path.startswith(target_path_prefix) and
                path.endswith(('.h', '.cc', '.S', '.mm')))

    defined_regex = input_api.re.compile(r'defined\(\s*(\w+)\s*\)')

    errors = []

    for f in input_api.AffectedSourceFiles(is_relevant_file):
        for line_number, line in f.ChangedContents():
            matches = defined_regex.findall(line)
            for macro in matches:
                # Automatically allow any PartitionAlloc internal macros
                if macro.startswith((
                        'PA_',
                        'PARTITION_ALLOC_',
                        'PARTITION_ALLOCATOR_',
                        'PAGE_ALLOCATOR_',
                )):
                    continue

                # Ignore header guards
                file_name = input_api.os_path.basename(f.LocalPath())
                file_guard_part = file_name.upper().replace('.', '_') + '_'
                if macro.endswith('_H_') and (
                        file_guard_part in macro or
                        macro.startswith('PARTITION_ALLOC_')):
                    continue

                if macro in ALLOWED_DEFINITIONS:
                    continue

                errors.append(
                    output_api.PresubmitError(
                        f'Unexpected macro `{macro}` in `defined()` in '
                        f'{f.LocalPath()}:{line_number}.\n'
                        f'If this is a new macro, please add it to the '
                        f'allowed list in PRESUBMIT.py if it is a '
                        f'compiler/system built-in.\n'
                        f'Otherwise, use PA_BUILDFLAG or PA_CONFIG '
                        f'instead.',
                        items=[f'{f.LocalPath()}:{line_number}: {line}']
                    )
                )

    return errors